1.JDBC的概念
JDBC(Java DataBase Connectivity,Java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成,所以JDBC本质就是一些操作数据库的jar包。
2.JDBC的作用
JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序,JDBC是Java程序操作数据库必要的接口,并且是持久层框架如Mybatis的基础,只有理解和熟练使用JDBC才能对框架的理解更加深入,知其然更知其所以然。总而言之,要使用Java操作数据库就要使用JDBC。
3.Connection,Statement,ResultSet的基本使用
JDBC的使用过程大概为:首先用加载对应的数据库驱动类到JVM中,然后使用数据库用户名和密码创建数据库连接,产生连接对象Connection,通过Connection对象可以得到SQL执行对象Statement,最后书写SQL语句然后用Statement对象执行SQL,如果是查询语句的话,用ResultSet对象来接受返回值。
所有的常量都是使用properties文件或者xml文件进行配置的,当然也可以用手动set,传参啥的,但是不建议。
示例代码:
import java.sql.*;
import java.util.Properties;
//使用基本的Statement进行数据库操作
public class JDBCDemo1 {
public static void main(String[] args) {
//定义一个properties对象来读取配置文件
Properties prop = new Properties( );
//定义一个数据库连接对象的引用
Connection conn = null;
//定义一个SQL执行对象的引用
Statement stat = null;
//定义一个结果集对象的引用
ResultSet rs = null;
String selectSql = "SELECT * FROM USER";
String addSql = "insert into USER values( '3','手冢国光', '1993.1.2')";
try {
//加载配置文件
prop.load(JDBCDemo1.class.getResourceAsStream("jdbc"));
//将数据库驱动类对象加载到JVM中
Class.forName(prop.getProperty("driverClassName"));
//使用API获得对数据库的connection
conn = DriverManager.getConnection(prop.getProperty("url"), prop.getProperty("username"), prop.getProperty("password"));
//通过连接对象生成一个执行SQL的statement对象
stat = conn.createStatement();
//测试JDBC的查询功能,用结果集对象来存取从数据库中查到的数据
rs = stat.executeQuery(selectSql);
//结果集的遍历
while(rs.next()) {
//ResultSet有很多API可供使用
//根据列的序号获取列的值(1是第一列)
System.out.print(rs.getString(1) + " ");
//通过列名获得列的值
System.out.println(rs.getString("name"));
}
//测试JDBC的插入功能(删除,更新和插入是一样的,只是SQL不同)
int count = stat.executeUpdate(addSql);
System.out.println("success insert " + count + " line");
} catch (Exception e) {
e.printStackTrace();
} finally {
try{
if(rs != null){
rs.close();
}
if(stat != null){
stat.close();
}
if(conn != null){
conn.close();
}
}catch (SQLException e){
e.printStackTrace();
}
}
}
}
使用了Properties文件
//数据库驱动类,使用的封装好的JDBC jar包
driverClassName = com.mysql.cj.jdbc.Driver
//使用jdbc方式连接MySQL数据库放在localhost端口号3306数据库名test,设置时间格式和编码格式
url = jdbc:mysql://localhost:3306/user?serverTimezone=UTC&characterEncoding=utf-8
//数据库的登录名
username = root
//数据库的登录密码
password = zhejiushimima
使用的最新的MySQL驱动,所以驱动类是com.mysql.cj.jdbc.Driver,不是com.mysql.jdbc.Driver,并且需要指定serverTimezone的值,可以选择不同的时区,这里就设置为serverTimezone=UTC
4.PrepareStatement的基本使用
Statement是最原始的SQL执行对象,存在很多问题,比如SQL注入,效率低等,所以开发中一律使用PrepareStatement。
PrepareStatement和Statement使用基本相同,只是产生PrepareStatement对象的时候,采用的是预编译,所以要提供缺失参数的SQL(用?占位符),然后在将参数set就行,最后示例代码中涉及到批处理的基本操作。
示例代码:
import java.sql.*;
import java.util.Properties;
//使用PrepareStatement进行预编译和批处理,更加安全高效
public class JDBCDemo2 {
public static void main(String[] args) {
//定义一个properties对象来读取配置文件
Properties prop = new Properties();
//定义一个数据库连接对象的引用
Connection conn = null;
//定义一个SQL执行对象的引用
PreparedStatement prep = null;
//定义一个结果集对象的引用
ResultSet rs = null;
//String selectSql = "SELECT * FROM USER WHERE NAME = ?";
String addSql = "insert into user values(?,?,?)";
try {
//加载配置文件
prop.load(JDBCDemo2.class.getResourceAsStream("jdbc"));
//将数据库驱动类对象加载到JVM中
Class.forName(prop.getProperty("driverClassName"));
//使用API获得对数据库的connection
conn = DriverManager.getConnection(prop.getProperty("url"), prop.getProperty("username"), prop.getProperty("password"));
//通过预编译SQL来生成一个prepareStatement对象
prep = conn.prepareStatement(addSql);
//向预编译的SQL中填入参数
prep.setString(1, "10");
prep.setString(2,"真田弦一郎");
prep.setDate(3, new Date(new java.util.Date().getTime()));
//批处理实例,但是只能用于更新的语句,不能用于查询的语句
//prep.addBatch();
//prep.executeBatch();
//这里直接执行预编译好的sql就好了
rs = prep.executeQuery();
//结果集的遍历
while (rs.next()) {
//ResultSet有很多API可供使用
//根据列的序号获取列的值(1是第一列)
System.out.print(rs.getString(1) + " ");
//通过列名获得列的值
System.out.println(rs.getString("name"));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
同样使用了前面的properties文件
预编译解决了很多问题,但是在高频率访问的情形下,服务器可能还是不堪重负,原因在于和数据库频繁的建立和断开连接,是很耗时的,这时候就需要数据库连接池来解决问题。
数据库连接池基本思想是当服务器启动之时,就直接建立与数据库的数个连接,然后当一个请求到达的时候,将一个可用连接分配给对应的请求,然后使用完毕在归还给连接池,并不进行实际的关闭,这样就解决了频繁建立和断开连接的问题。
5.DBCP数据库连接池基本使用
DBCP(DataBase Connection Pool)数据库连接池,是java数据库连接池的一种,由Apache开发,通过数据库连接池,可以让程序自动管理数据库连接的释放和断开。
数据库连接池这里的主要涉及到的是启动配置。
DBCP的配置采用的properties文件:
//数据库驱动类,使用的封装好的JDBC jar包
driverClassName = com.mysql.cj.jdbc.Driver
//使用jdbc方式连接MySQL数据库放在localhost端口号3306数据库名test,设置时间格式和编码格式
url = jdbc:mysql://localhost:3306/user?serverTimezone=UTC&characterEncoding=utf-8
//数据库的登录名
username = root
//数据库的登录密码
password = zhejiushimima
//连接池启动时创建的连接数(默认为0)
initalSize = 10
//连接池中可同时连接的最大连接数(默认为8)
maxActive = 5
//连接池中允许的最大空闲数(默认是8,负数表示不受限制)
maxIdle = 5
//连接池中允许的最小空闲连接数
minIdle = 3
//如果连接不够用的时候,等待的最长时间(默认是无限,建议调整为一个定值,防止饿死)
maxWait = 60000
示例代码:
public class JDBCDemo3 {
public static void main(String[] args){
Properties prop = new Properties();
ResultSet rs = null;
try {
//加载配置文件
prop.load(JDBCDemo3.class.getResourceAsStream("dbcp"));
//根据配置文件来构造数据库连接池
DataSource ds = BasicDataSourceFactory.createDataSource(prop);
//从连接池中取连接
Connection conn = ds.getConnection();
//测试
PreparedStatement prep = conn.prepareStatement("SELECT * from USER ");
rs = prep.executeQuery();
while(rs.next()){
System.out.println(rs.getString(2));
}
} catch (Exception e) {
e.printStackTrace();
}
}
6.C3P0数据库连接池基本使用
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等,比DBCP好一些,支持自动关闭连接。
使用类似,C3P0的配置有三种方法,一种是使用set方法手动配置,一种是使用properties文件,最后是使用xml文件,这里是使用xml文件配置,这些配置文件都可以去官网copy,意义也基本都很好理解。
xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="automaticTestTable">con_test</property>
<property name="checkoutTimeout">30000</property>
<property name="idleConnectionTestPeriod">30</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property>
<!-- MySQL的配置 -->
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/user?serverTimezone=UTC&characterEncoding=utf-8</property>
<property name="user">root</property>
<property name="password">zhejiushimiam</property>
<user-overrides user="test-user">
<property name="maxPoolSize">10</property>
<property name="minPoolSize">1</property>
<property name="maxStatements">0</property>
</user-overrides>
</default-config>
<!-- This app is massive! -->
<named-config name="intergalactoApp">
<property name="acquireIncrement">50</property>
<property name="initialPoolSize">100</property>
<property name="minPoolSize">50</property>
<property name="maxPoolSize">1000</property>
<!-- intergalactoApp adopts a different approach to configuring statement caching -->
<property name="maxStatements">0</property>
<property name="maxStatementsPerConnection">5</property>
<!-- he's important, but there's only one of him -->
<user-overrides user="master-of-the-universe">
<property name="acquireIncrement">1</property>
<property name="initialPoolSize">1</property>
<property name="minPoolSize">1</property>
<property name="maxPoolSize">5</property>
<property name="maxStatementsPerConnection">50</property>
</user-overrides>
</named-config>
</c3p0-config>
示例代码:
public class JDBCDemo4 {
public static void main(String[] args){
//手动指定xml配置文件的路径,如果不手动指定,默认是加载ClasPath下面的c3p0-config.xml文件,所以要放在src根目录下
System.setProperty("com.mchange.v2.c3p0.cfg.xml", System.getProperty("user.dir")+"/servletWeb/src/c3p0-config.xml");
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
Connection conn = ds.getConnection();
//测试,有了配置文件,就很轻松了
PreparedStatement prep = conn.prepareStatement("SELECT * FROM USER");
ResultSet rs = prep.executeQuery( );
while(rs.next()){
System.out.println(rs.getString(2));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
7.数据库事务
除了以上的基本使用还有就是JDBC支持数据库的事务设置,可以设置事务手动提交,以便回滚,也可以设置数据库事务隔离级别等等。
所有的jar包都去官网下载二进制zip文件,然后解压之后就可以引入使用了。
数据库是MySQL数据库
数据库驱动jar包是mysql-connector-java-8.0.11.jar.
DBCP需要三个jar包:
commons-dbcp2-2.3.0.jar
commons-logging-1.2.jar
commons-pool2-2.5.0.jar
C3P0需要两个个jar包:
c3p0-0.9.5.2.jar
mchange-commons-java-0.2.11.jar