JDBC

1. 简介

JDBC全称Java DataBase Connectivity,即Java数据库连接。JDBC是一套标准,是Java与各大数据库厂商共同定制的一套接口。下面以MySQL为例进行讲解。

在Java程序中使用JDBC

  1. 引入jar文件,jar文件要与数据库的版本对应。
  2. 加载数据库驱动 (JavaSE项目中可以省略 , JavaWeb项目必须编写此步骤)
Class.forName("com.mysql.jdbc.Driver"); // mysql6版本以下
Class.forName("com.mysql.cj.jdbc.Driver"); //mysql6版本以上
  1. 通过驱动管理器, 获取JDBC连接对象.
Connection conn = DriverManager.getConnection("数据库连接地址","帐号","密码");
// 数据库连接地址格式: 主协议:子协议://ip地址:端口号/数据库名称
// mysql的连接地址: jdbc:mysql://localhost:3306/javadb
// oracle的连接地址: jdbc:oracle:thin:@localhost:1521:ORCL
  1. 通过连接对象, 创建SQL执行对象 (SQL执行环境)
Statement state = conn.createStatement();
  1. 通过SQL执行对象 ,执行SQL语句.
state.execute(String sql语句);
  1. 释放资源
state.close();
conn.close();

不同版本mysql的jar文件下载:

https://www.javatt.com/p/83779

2. JDBC中常用的类型与方法

  1. DriverManager : 驱动管理器
    常用方法:
  • 获取数据库连接:
static Connection getConnection(String 数据库地址,String 账号 ,String 密码);
  1. Connection : 数据库连接对象
    常用方法:
  • 创建SQL执行对象:
//1. 通常执行无参的sql语句时创建Statement实例
Statement createStatement(); 
//2. 通常执行包含参树的sql语句时创建PrepareStatement实例,并对SQL语句进行预编译处理
PrepareStatement prepareStatement();
  • 事务操作,只针对当前连接对象生效。
setAutoCommit(false); //开启事务
rollback();	//回滚事务
commit(); //提交事务
  1. Statement/PrepareStatement : SQL执行对象
    常用方法:
  • 执行SQL语句(查询语句(有结果集)返回true,其它语句返回false)
boolean execute(String sql);
  • 执行DML语句(INSERT UPDATE DELETE) 和 DDL语句(create alter drop)(返回int值,表示语句对数据库表格的影响行数 !)(通常我们认为 返回值>0 表示执行成功。)
int executeUpdate(String sql);
  • 执行DQL语句 (select) 返回结果集对象
ResultSet executeQuery(String sql);

PrepareStatement是Statement的子类,扩展了Statement类,实现了动态实时执行SQL语句,可在运行时提供参数。

除了上面三个常用的方法外,还有一个特有的方法:给指定索引的参数设置值,索引从1开始。

setXXX(int 索引,XXX 值)

  1. ResultSet : 结果集对象 (指的是一个select语句的查询结果)
    常用方法:
  • 控制游标移动的常用方法:
  • 控制游标向下一行移动。移动成功返回true,下一行不存在移动失败,返回false
boolean next();
  • 其他的一些游标移动的方法
boolean privious(); //控制游标向上一行移动。
boolean absolute(int 行号)//控制游标向指定行移动。
boolean beforeFirst();//控制游标移动到第一行。
boolean afterLast();//控制游标移动到最后一行,
  • 获取游标指向行的字段值的常用方法:
XXX getXXX(String 列名);  //根据字段名得到此字段的值,XXX表示该字段的类型

XXX getXXX(int 字段的索引);//根据字段的索引,得到字段的值,索引从1开始

3. PreparedStatement 预编译的SQL执行环境

内部实现原理:

将未拼接参数的SQL语句,作为SQL指令,先传递给数据库进行编译。再将参数传递给数据库,此时传递的参数不会再作为指令执行, 只会被当作文本存在。

操作流程与Statement基本一致:

  1. 得到一个PreparedStatement 对象
PreparedStatement state = conn.prepareStatement("预编译的SQL语句");

预编译的SQL语句编写

需要填充参数的位置,使用?代替即可 例如:

select id from users where username=? and password=?
  1. 参数填充
/* setXXX中XXX指的是数据类型
 * 参数1: index : SQL语句中?的索引值,从1开始
 * 参数2: value : 填充的参数值.
 */
state.setXXX(int index,XXX value);
  1. 执行
state.execute();

……

PreparedStatement与Statement性能比较

看数据库类型,在mysql中,preparedStatement原理是拼接SQL,所以Statement比preparedStatement性能高。

在Oracle中,preparedStatement原理是对SQL指令进行预处理,再传递的参数不具备特殊含义.有更好
的SQL缓存策略,PreparedStatement性能更高。

使用PreparedStatement可以避免sql注入的安全问题

SQL注入是指在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。

举个简单的例子:

程序定义的原查询语句:

select * from users where username='' and password='密码'

拼接后:

select * from users where username='xxx' and password='xxx' or '1'='1'

or '1'='1'这个条件永远都是成立的。

4. DAO/静态工厂模式

DAO(Data Access Object)是一个数据访问接口。夹在业务逻辑与数据库资源中间,与数据库打交道。

为了建立一个健壮的Java应用,应该将所有对数据源的访问操作抽象封装在一个公共API中。用程序设计的语言来说,就是建立一个接口,接口中定义了此应用程序中将会用到的所有事务方法。在这个应用程序中,当需要和数据源进行交互的时候则使用这个接口,并且编写一个单独的类来实现这个接口在逻辑上对应这个特定的数据存储。

DAO模式是标准的JavaEE设计模式之一,我们一般使用这个模式把底层的数据访问操作和上层的商务逻辑分开。一个典型的DAO实现有下列几个组件:

  • 一个DAO工厂类
  • 一个DAO接口;
  • 至少一个实现DAO接口的具体类;
  • 数据传递对象(有些时候叫做Bean对象).

工厂方法设计模式 ( 静态工厂方法模式 )

工厂方法模式一种创建对象的模式.

工厂方法模式基于"输入",应用在超类和多个子类之间,这种模式将创建对象的责任转移到工厂类;

工厂设计模式的优点:

  1. 面向接口编程,体现了面向对象的思想
  2. 降低了耦合, 将创建对象的工作转移到了工厂类

// 水果接口 public interface BaseFruitDao { void eat(); } //苹果 (水果的一种) public class AppleDao implements Fruit{ @Override public void eat() { System.out.println("吃苹果"); } } //香蕉 (水果的一种) public class BananaDao implements Fruit{ @Override public void eat() { System.out.println("吃香蕉"); } } // 静态工厂类 public class FruitDaoFactory { public static FruitDao get(){ //return new AppleDao(); return new BananaDao(); } }

这样我们在需要香蕉对象时,就可以通过FruitDaoFactory这个工厂类的get方法获取

FruitDao f1 = FruitDaoFactory.get();

5. 批处理

将多条语句,放到一起批量处理 。

批处理的原理: 将多条SQL语句,转换为一个SQL指令。显著的提高大量SQL语句执行时的数据库性能。

//Statement对象使用流程:

    //1. 得到Statement对象
        Statement state = conn.createStatement();
    //2. 将一条SQL语句, 加入到批处理中.
        state.addBatch(String sql);
    //3. 执行批处理
        state.executeBatch();
    //4. 清空批处理
        state.clearBatch();

//PreparedStatement对象使用流程:

    //1. 得到PreparedStatement对象
        PreparedStatement state = conn.prepareStatement("预编译的SQL");
    //2. 填充预编译的参数
        state.setXXX(索引,填充参数);
    //3. 将一条填充完毕参数的SQL, 加入到批处理中.
        state.addBatch();
    //4. 执行批处理
        state.executeBatch();
    //5. 清空批处理
        state.clearBatch();

6.数据库连接池

数据库连接池用于缓存连接。

当我们需要使用连接时,可以不用再创建连接 ,直接从连接池中获取连接。

  • 当连接池中存在空闲连接时, 会将空闲连接给到程序使用。
  • 当连接池中不存在空闲连接时,且连接池未满时,则创建连接提供给程序使用,并在程序使用完毕后,缓存连接
  • 当连接池中不存在空闲连接时, 且连接池已满时 ,则排队等候空闲连接的出现。

注意:

  • 使用连接池中的连接对象操作数据库时,操作完毕依然需要释放连接(调用close()).
  • 连接池中的连接在设计时,使用了动态代理设计模式+装饰者设计模式。我们调用它的close方法,代理没有关闭这个连接,而是将连接重新放入了池中。

我们常用的连接池有DBCP基础连接池和德鲁伊连接池。

Properties 作为配置文件

Properties类 是Java中的Map集合的实现类.

.properties文件 用于通过文件描述一组键值对,可以快速的转换为Properties类的对象。

文件中内容的格式:文件内容都是字符串 ,键与值之间通过等号连接 ,多个键值对之间换行分割。例如:

url = xxx username = xxx password = xxx

将文件转换为集合对象的步骤:

  1. 创建Properties对象
    Properties ppt = new Properties();
  2. 创建一个字节输入流 ,指向.properties文件
    InputStream is = new FileInputStream("文件地址");
  3. 将字节输入流,传递给properties对象,进行加载。
    ppt.load(is);

我们可以用Properties 作为配置文件存储我们的数据库连接

使用步骤:

  1. 引入相关的jar文件,
  • 使用DBCP连接池就引入dbcp.jar和poll.jar
  • 使用德鲁伊连接池就引入druid-1.0.9.jar
  1. 将配置文件引入
  2. 将配置文件,转换为Properties对象
Properties ppt = new Properties();
ppt.load(配置文件的输入流);
  1. 通过连接池的工厂类的创建连接方法创建连接池
DataSource ds = BasicDataSourceFactory.createDataSource(ppt); // DBCP连接池
DataSource ds = DruidDataSourceFactory.createDataSource(ppt); //德鲁伊连接池
  1. 从连接池中获取连接对象
Connection conn = ds.getConnection();

关于连接池更多的内容可参考下面这篇文章


关于一些常用连接池的比较可参考下面这篇文章