1、JDBC是什么?
Java DataBase Connectivity (Java语言连接数据库)
2、JDBC本质是什么?
JDBC是SUN公司制定的一套接口。
接口都有调用者和设计者。
面向接口调用,面向接口写实现类,这都属于面向接口编程。
一、JDBC连接数据库的步骤
1. 注册驱动
告诉Java程序,即将要连接的是哪个品牌的数据库
1. 第一种方式
主要是使用了DriverManager类中的静态方法:static void registerDriver(Driver driver);
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
2. 第二种方式(常用)
Class.forName("com.mysql.jdbc.Driver");
//会抛出ClassNotFoundException异常
这一步骤是因为使用反射将类文件加载进内存时会执行静态代码块中的程序,而在com.mysql.jdbc.Driver类中正好有静态代码块的内容。如下:
因此,使用反射注册驱动也是执行了DriverManager的注册驱动的代码。
2. 获取连接
表示JVM的进程和数据库之间的通道打开了,这属于进程之间的通信,重量级的,使用完一定要关闭。
Connection conn = DriverManager.getConnection(String url);
Connection conn = DriverManager.getConnection(String url,String user,String password);
3. 获取数据库操作对象
主要是使用了Connection类中的以下两个方法来获取:
Statement createstatement( );
Preparedstatement prepareStatement(String sql);
专门执行SQL语句的对象
java.sql.Statement接口与java.sql.PreparedStatement接口;
其中PreparedStatement接口继承自Statement接口,是预编译的数据库操作对象。
使用Statement接口容易产生SQL语句注入的问题,所以在以后获取数据库操作对象时建议使用PreparedStatement接口。
Statement statement = conn.createStatement();
PreparedStatement preparedStatement = conn.prepareStatement();
4. 执行SQL语句
DQL DML....
//执行DML语句,返回值为数据库中影响的行数
int count = statement.executeUpdate(sql);
//执行DQL语句
ResultSet resultSet = statement.executeQuery(sql);
5. 处理查询结果集
只有当第四步执行的是select语句是,才有这一步。
6. 释放资源
使用完资源之后一定要关闭,为了保证资源一定释放,在finally语句块中关闭。
且遵循从小到大的原则关闭,分别对其try...catch
二、JDBC编程的六步(代码示例)
1.增加操作
1. java.sql.Statement版
package JDBC;
import java.sql.Driver;
import java.sql.Statement;
import java.sql.Connection;
import java.sql.SQLException;
import static java.sql.DriverManager.*;
public class JDBCTest {
public static void main(String[] args){
Statement statement;
Connection conn;
try{
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//Driver drier = new com.mysql.jdbc.Driver();//多态,父类型指向子类对象
//DriverManager.registerDriver(driver);
//2.获取连接
String url = "jdbc:mysql://127.0.0.1:3306/student";
String user = "admin";
String password = "123123";
conn = getConnection(url,user,password);
//3.获取数据库操作对象(Statement专门执行SQL语句)
statement = conn.createStatement();
//4.执行SQL
String sql = "insert into student(sno,sname,sage) values (001,'张三',23)";
//专门执行DML语句的(insert,update,delete)
//返回值是:影响数据库中的记录条数
int count = statement.executeUpdate(sql);
}catch(SQLException e){
e.printStrackTrace;
}catch(ClassNotFoundException e){
e.printStrackTrace;
}finally{
//6.释放资源
//为了保证资源一定释放,在finally语句块中关闭,且遵循从小到大的原则关闭
//分别对其try...catch
try{
if(statement != null){
statement.close();
}
}catch(SQLException e){
e.printStackTrace();
}
try{
if(conn != null){
conn.close();
}
}catch(SQLException e){
e.printStackTrace();
}
}
}
}
2. java.sql.PreparedStatement版
import java.sql.Driver;
import java.sql.PreparedStatement;
import java.sql.Connection;
import java.sql.SQLException;
import static java.sql.DriverManager.*;
public class JDBCTest {
public static void main(String[] args){
PreparedStatement ps;
Connection conn;
try{
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//Driver drier = new com.mysql.jdbc.Driver();//多态,父类型指向子类对象
//DriverManager.registerDriver(driver);
//2.获取连接
String url = "jdbc:mysql://127.0.0.1:3306/student";
String user = "admin";
String password = "123123";
conn = getConnection(url,user,password);
//3.获取数据库操作对象(preparedStatement专门执行SQL语句)
//专门执行DML语句的(insert,update,delete)
String sql = "insert into student(sno,sname,sage) values (?,?,?)";
ps = conn.prepareStatement(sql);
//给占位符传值,起始值为1。
ps.setInt(1,001);
ps.setString(2,"王五");
ps.setInt(3,23);
//4.执行SQL
//返回值是:影响数据库中的记录条数
int count = ps.executeUpdate();
}catch(SQLException e){
e.printStrackTrace;
}catch(ClassNotFoundException e){
e.printStrackTrace;
}finally{
//6.释放资源
//为了保证资源一定释放,在finally语句块中关闭,且遵循从小到大的原则关闭
//分别对其try...catch
try{
if(ps != null){
ps.close();
}
}catch(SQLException e){
e.printStackTrace();
}
try{
if(conn != null){
conn.close();
}
}catch(SQLException e){
e.printStackTrace();
}
}
}
}
2.删除操作
package JDBC;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.DriverManager;
public class JDBCTest{
public void main(String[] args){
Connection conn;
Statement statement;
try{
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//Driver driver = new com.mysql.jdbc.driver();
//DriverManager.registerDriver(driver);
//2.获取连接
String url = "jdbc:mysql://127.0.0.1:3306/student";
String user = "admin";
String password = "123123";
conn = DriverManager.getConnection(url,user,password);
//3.获取数据库操作对象
statement = conn.createStatement();
//4.执行SQL
String sql = "delete from student where sno = 001";
int count = statement.executeUpdate(sql);
}catch(SQLException e){
e.printStackTrace();
}catch(ClassNotFoundException e){
e.printStrackTrace;
}finally{
//6.关闭资源
try{
if(statement != null){
statement.close();
}
}catch(SQLException e){
e.printStackTrace();
}
try{
if(conn != null){
conn.close();
}
}catch(SQLException e){
e.printStackTrace();
}
}
}
}
3.修改操作
package JDBC;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.DriverManager;
public class JDBCTest{
public void main(String[] args){
Connection conn;
Statement statement;
try{
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//DriverManager.registerDriver(new com.mysql.jdbc.Driver());
//2.获取连接
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/student","admin","123123");
//3.获取数据库操作对象
statement = conn.createStatement();
//4.执行sql语句
statement.executeUpdate("update student set sname = '李四',sage = 20 where sno = 100");
}catch(SQLException e){
e.printStackTrace();
}catch(ClassNotFoundException e){
e.printStrackTrace;
}finally {
//6.关闭资源
try{
if(statement != null){
statement.close();
}
}catch (SQLException e){
e.printStackTrace();
}
try{
if (conn != null){
conn.close();
}
}catch (SQLException e){
e.printStackTrace();
}
}
}
}
4.查找操作
1. java.sql.Statement版
package JDBC;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.DriverManager;
import java.sql.ResultSet;
public class JDBCTest{
public static void main(String[] args){
Connection conn;
Statement statement;
ResultSet resultSet;
try{
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接
conn = DriverManager.getConnection("jsbc:mysql://localhost:3306/student","admin","123123");
//3.获取数据库操作对象
statement = conn.createStatement();
//4.执行SQL语句
String sql = "select sno,sname,sage from student";
resultSet = statement.executeQuery(sql); //得到查询结果集
//5.处理查询结果集
while(resultSet.next()){ //获取每一行
/*
//(1)通过下标的方式获取列值,下表是从1开始的。
String sno = resultSet.getString(1);
String sname = resultSet.getString(2);
String sage = resultSet.getString(3);
*/
/*
//(2)通过列名的方式获取列值。
String sno = resultSet.getString("sno");
String sname = resultSet.getString("sname");
String sage = resultSet.getString("sage");
*/
//(3)通过获取指定类型来获取列值。
int sno = resultSet.getInt("sno");
String sname = resultSet.getString("sname");
int sage = resultSet.getInt("sage");
}
}catch(SQLException e){
e.printStackTrace();
}finally{
//6.关闭资源
try{
if(resultSet != null){
resultSet.close();
}
}catch(SQLException e){
e.printStackTrace();
}
try{
if(statement != null){
statement.close();
}
}catch(SQLException e){
e.printStackTrace();
}
try{
if(conn != null){
conn.close();
}
}catch(SQLException e){
e.printStackTrace();
}
}
}
}
2. java.sql.PreparedStatement版
import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
import java.sql.PreparedStatement;
import java.sql.DriverManager;
import java.sql.ResultSet;
public class JDBCTest{
public static void main(String[] args){
Connection conn;
PreparedStatement ps;
ResultSet resultSet;
try{
//1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接
conn = DriverManager.getConnection("jsbc:mysql://localhost:3306/student","admin","123123");
//3.获取数据库操作对象
String sql = "select sno,sname,sage from student where sno = ?";
ps = conn.prepareStatement(sql);
//为占位符传值
ps.setInt(1,001);
//4.执行SQL语句
resultSet = ps.executeQuery(); //得到查询结果集
//5.处理查询结果集
if(resultSet.next()){
int sno = resultSet.getInt("sno");
String sname = resultSet.getString("sname");
int sage = resultSet.getInt("sage");
}
}catch(SQLException e){
e.printStackTrace();
}finally{
//6.关闭资源
try{
if(resultSet != null){
resultSet.close();
}
}catch(SQLException e){
e.printStackTrace();
}
try{
if(ps != null){
ps.close();
}
}catch(SQLException e){
e.printStackTrace();
}
try{
if(conn != null){
conn.close();
}
}catch(SQLException e){
e.printStackTrace();
}
}
}
}
三、 JDBCUtils工具类
1、 不适用连接池工具类
package utils;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;
public class JDBCUtils {
private static String url;
private static String user;
private static String password;
static {
try {
// 创建Properties集合类
Properties properties = new Properties();
ClassLoader classLoader = JDBCUtils.class.getClassLoader();
URL resourceURL = classLoader.getResource("jdbc.properties");
String path = resourceURL.getPath();
// 加载文件
properties.load(new FileReader(path));
// 获取文件值
url = properties.getProperty("url");
user = properties.getProperty("user");
password = properties.getProperty("password");
// 注册驱动
Class.forName(properties.getProperty("driver"));
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获取数据库连接的方法
* @return
*/
public static Connection getConnection(){
Connection connection = null;
try {
// 获取数据库连接对象
connection = DriverManager.getConnection(url,user,password);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return connection;
}
/**
* 关闭数据库连接对象
* @param connection
*/
public static void close(Connection connection){
if(connection != null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
2、 使用Druid连接池的工具类
package com.utils;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class JDBCUtils {
private static DruidDataSource dataSource;
static {
// 加载配置文件
Properties properties = new Properties();
// 读取jdbc.properties属性配置文件
InputStream inputStream = JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
try {
// 从流中加载数据
properties.load(inputStream);
// 获取连接池对象
dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取数据库连接对象
* @return 如果返回null说明获取连接池失败。反之,成功。
*/
public static Connection getConnection(){
Connection connection = null;
try {
connection = dataSource.getConnection();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return connection;
}
/**
* 关闭数据库连接等对象
* @param connection 数据库连接对象
*/
public static void close(Connection connection){
if(connection != null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
三、PreparedStatement与Statement比较
1、 原理比较
- Statement存在SQL注入问题,PreparedStatement解决了SQL注入问题
- Statement是编译一次执行一次,而PreparedStatement编译一次执行多次,PreparedStatement执行效率高一点。
- PreparedStatement会在编译阶段做类型的安全检查。
2、 代码比较
- Statement是通过connection.creatStatement()创建,PreparedStatement是通过connection.preparedStatement(sql)创建,且在创建的时候需要传入SQL语句。
- 在执行SQL语句步骤时,Statement需要在执行的executeXxx(sql)中传入SQL语句,而PreparedStatement在创建的时候就传入SQL语句了,不需要在此步骤再次穿SQL语句。
四、JDBC事务的处理
1. 开启事务
JDBC事务的提交是采用自动提交机制,可以进行手动提交。
首先要开启事务:
需要在获取连接之后添加以下代码:
conn.setAutoCommit(false);//开启事务
2. 提交事务
在完成上述的开启事务之后,JDBC不会自动提交事务,需要手动提交;
需要在最后添加以下代码:
conn.commit();//提交事务
3. 回滚事务
添加一个try…catch语句来进行事务回滚。添加的代码如下:
if(conn != null){
try{
conn.rollback();
}catch(SQLException e1){
e1.printStrackTrace;
}
}
添加代码如图所示:
五、 C3P0数据库连接池
1、 使用步骤
- 导入jar包
c3p0-版本号.jar
mchange-commons-java-版本号.jar
mysql-connector-java-版本号-bin.jar - 定义配置文件
1. 名称
c3p0.properties或者是c3p0-config.xml
2. 路径
直接将文件放在src目录下即可。 - 创建核心对象
数据库连接池对象:ComboPooledDataSource - 获取连接:getConnection()
2、 c3p0-config.xml配置信息
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!--默认配置-->
<default-config>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/database</property>
<property name="user">root</property>
<property name="password">123123</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>
</default-config>
<!--配置连接池mysql-->
<named-config name="mysql">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/database</property>
<property name="user">root</property>
<property name="password">123123</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>
</named-config>
<!--配置连接池2-->
......
</c3p0-config>
3、 c3p0使用示例
// 使用默认的连接池
ComboPooledDataSource dataSource = new ComboPooledDataSource();
// 使用带有标志名的连接池
ComboPooledDataSource dataSource = new ComboPooledDataSource("mysql");
// 从连接池中取用一个连接
Connection connection = dataSource.getConnection();
// 释放连接
connection.close();
六、 Druid数据库连接池
1、 使用步骤
- 导入jar包
druid-版本号.jar
mysql-connector-java-版本号-bin.jar - 定义配置文件
配置文件为properties文件
配置文件可以是任意名称,可以将配置文件放在任意位置 - 加载配置文件
Properties properties = new Properties();
InputStream inputStream = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
properties.load(inputStream);
- 获取数据库连接对象
通过工厂方式来获取:DruidDataSourceFactory - 获取连接:getConnection();
2、 .properties配置文件信息
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/database
user=root
password=123123
# 最大初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=10
3、 Druid使用示例
// 加载配置文件
Properties properties = new Properties();
InputStream inputStream = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
properties.load(inputStream);
// 获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
// 获取连接
Connection connection = dataSource.getConnection();
七、 DBUtils的使用
1、 commons-dbutils简介
commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能。因此dbutils成为很多不喜欢hibernate的公司的首选。
commons-dbutilsAPI介绍:
org.apache.commons.dbutils.QueryRunner
org.apache.commons.dbutils.ResultSetHandler
工具类
org.apache.commons.dbutils.DbUtils
2、 QueryRunner类使用讲解
该类简单化了SQL查询,它与ResultSetHandler组合在一起使用可以完成大部分的数据库操作,能够大大减少编码量。
QueryRunner类提供了两个构造方法:
- 默认的构造方法
- 需要一个 javax.sql.DataSource 来作参数的构造方法。
2.1. QueryRunner的主要方法
执行一个查询操作,在这个查询中,对象数组中的每个元素值被用来作为查询语句的置换参数。该方法会自行处理 PreparedStatement 和 ResultSet 的创建和关闭。
public Object query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException;
几乎与第一种方法一样;唯一的不同在于它不将数据库连接提供给方法,并且它是从提供给构造方法的数据源(DataSource) 或使用的setDataSource 方法中重新获得 Connection。
public Object query(String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException;
执行一个不需要置换参数的查询操作。
public Object query(Connection conn, String sql, ResultSetHandler<T> rsh) throws SQLException;
用来执行一个更新(插入、更新或删除)操作。
public int update(Connection conn, String sql, Object[] params) throws SQLException;
用来执行一个不需要置换参数的更新操作。
public int update(Connection conn, String sql) throws SQLException;
2.2. update()方法的使用示例
没有使用连接池的方式:
public void update(){
// 没有使用数据源,因此使用无参构造
QueryRunner queryRunner = new QueryRunner();
Connection connection = JDBCUtils.getConnection();
String sql = "update t_book set price=? where id=?";
Object[] params = {11.11,21};
try {
int result = queryRunner.update(connection,sql,params);
System.out.println("result的值为:" + result);
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
if(connection != null){
DbUtils.closeQuietly(connection);
}
}
}
使用连接池的方式:
public void testJDBCUtils(){
// 使用连接池,因此使用带参构造,先通过工具类获取连接池
QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSourse());
String sql = "update t_book set price=? where id=?";
Object[] params = {12.12,21};
try {
int result = queryRunner.update(sql,params);
System.out.println("result的值为:" + result);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
2.3. query()方法的使用示例
public void query(){
QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSourse());
String sql = "select * from t_user";
try {
List<User> result = queryRunner.query(sql,new BeanListHandler<User>(User.class));
System.out.println("result的值为:" + result);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
3、 ResultSetHandler接口使用讲解
该接口用于处理java.sql.ResultSet,将数据按要求转换为另一种形式。
ResultSetHandler接口提供了一个单独的方法:Object handle (java.sql.ResultSet .rs)
3.1. ResultSetHandler接口的实现类
ArrayHandler:把结果集中的第一行
数据转成对象数组。
ArrayListHandler:把结果集中的每一行
数据都转成一个数组,再存放到List中。
BeanHandler:将结果集中的第一行
数据封装到一个对应的JavaBean实例中。
BeanListHandler:将结果集中的每一行
数据都封装到一个对应的JavaBean实例中,存放到List里。
ColumnListHandler:将结果集中某一列
的数据存放到List中。
KeyedHandler(name):将结果集中的每一行
数据都封装到一个Map里,再把这些map再存到一个map里,其key为指定的key。
MapHandler:将结果集中的第一行
数据封装到一个Map里,key是列名,value就是对应的值。
MapListHandler:将结果集中的每一行
数据都封装到一个Map里,然后再存放到List