一. JDBC概述

1. 什么是JDBC

·JDBC(Java Data Base Connectivity) Java连接数据库的技术
·是一种执行SQL的API, 可以为多种关系型数据库提供统一的访问
·它是由一组用java语言编写的类和接口组成, 是Java访问数据库的标准规范

04_JDBC:Java数据库连接技术 - 图8
2. JDBC的原理
04_JDBC:Java数据库连接技术 - 图9总结:

JDBC就是由sun公司定义的一套操作所有关系型数据库的规则(接口), 而数据库厂商需要实现这套接口, 厂商的实现类在引入的数据库驱动jar包中
程序员需要学习JDBC提供的接口规范来应用jar中的实现类

二. JDBC实现查询

1. 数据准备

— 创建表 jdbc_user
create table jdbc_user(
id int primary key auto_increment,
username varchar(10),
password varchar(10),
age int
);
— 插入数据
insert into jdbc_user (username, password, age) values
(‘zs’, ‘000000’,18),
(‘ls’,’111111’,24),(‘ww’, ‘222222’,20);

2. 引入MySQL jar包

·将MySQL的jar包添加到项目中的lib文件夹, 并将jar添加到libraries

3. API使用: 1.注册驱动

·JDBC规范中的驱动接口: java.sql.Driver
·MySQL驱动包提供的实现类: com.mysql.jdbc.Driver
04_JDBC:Java数据库连接技术 - 图10

  1. 代码实现 | public class JdbcDemo1 {
    _
    _public static void
    main(String[] args_) _throws ClassNotFoundException, SQLException {
    __
    //1.注册驱动(类加载)
    _Class._forName
    (“com.mysql.cj.jdbc.Driver”);
    }
    __}
    | | —- |

2) 注册驱动的目的?

//Driver类是MySQL提供的数据库驱动类, 实现了JDBC的Driver接口public class Driver extends NonRegisteringDriver implements java.sql.Driver {
__
//无参构造
public Driver_() _throws SQLException {
}
//静态代码块, 一旦执行了类加载, static代码块就会自动的执行
static {
__ _try
{
_
/
DriverManager 是驱动的管理类, 可以通过驱动管理类获取数据库的连接
registerDriver(new Driver()) 注册驱动的方法
*/
_DriverManager._registerDriver
_(_new com.mysql.cj.jdbc.Driver());
} _catch (_SQLException var1) {
_
_throw new
RuntimeException(“Can’t register driver!”);
}
}
}

注意: JDBC4.0之后, 在每个驱动jar包中META-INF/services目录下提供了一个名为java.sql.Driver的文件

4. API使用: 2.获取连接

·JDBC提供了Connection接口, 代表一个数据库连接接口
·MySQL通过DriverManager类中的静态方法getConnection可以获取连接
04_JDBC:Java数据库连接技术 - 图11

1) getConnection方法3个连接参数的说明
04_JDBC:Java数据库连接技术 - 图12

2) url主要组成部分的详细说明

jdbc:mysql://localhost:3306/bjsxt04
?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai

·JDBC规定url的格式由三部分组成,每个部分中间使用冒号分隔
第一部分是协议 jdbc,这是固定的
第二部分是子协议,就是数据库名称,连接mysql数据库,第二部分当然是mysql了
第三部分是由数据库厂商规定的,我们需要了解每个数据库厂商的要求,mysql的第三部分分别由数据库服务器的IP地址(localhost)、端口号(3306),以及要使用的数据库名称组成
04_JDBC:Java数据库连接技术 - 图13**

2) 代码实现

public class JdbcDemo1 {
_
_public static void
main(String[] args_) _throws ClassNotFoundException, SQLException {
__
//1.类加载 加载驱动
_Class._forName
(“com.mysql.cj.jdbc.Driver”);
//2 获取数据库连接 String url = “jdbc:mysql://localhost:3306/bjsxt04
?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai”; _Connection connection = DriverManager._getConnection(url,,“root”,“root”);
}
__}

5. API使用: 3.获取SQL执行对象

04_JDBC:Java数据库连接技术 - 图14·通过Connection 的 createStatement方法 获取sql语句执行对象
**1) 代码实现

| public class JdbcDemo1 {
_
_public static void
main(String[] args_) _throws ClassNotFoundException, SQLException {
__
//1.类加载 加载驱动
_Class._forName
(“com.mysql.cj.jdbc.Driver”);

//2 获取数据库连接
_String url = “jdbc:mysql://localhost:3306/bjsxt04
?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai”;
Connection connection = DriverManager._getConnection
(url,“root”,“root”);

  1. _//3.获取SQL语句执行对象<br /> _Statement statement = connection.createStatement**_()_**;<br /> **_}<br />__}_** |

| —- |

6. API使用: 4.执行SQL, 获取返回结果

04_JDBC:Java数据库连接技术 - 图15·用于发送SQL语句给MySQL服务器,执行SQL 语句并返回它所生成结果

1) 代码实现

| public class JdbcDemo1 {
_
_public static void
main(String[] args_) _throws ClassNotFoundException, SQLException {
__
//1.类加载 加载驱动
_Class._forName
(“com.mysql.cj.jdbc.Driver”);

    _//2 获取数据库连接<br />        _String url = **"jdbc:mysql://localhost:3306/bjsxt04**<br />**?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai"**;<br />        Connection connection = DriverManager._getConnection_**_(_**url,**"root"**,**"root"_)_**;

    _//3.获取SQL语句执行对象<br />        _Statement statement = connection.createStatement**_()_**;

    _//4.执行SQL语句, 并拿到返回结果<br />        _String sql = **"select **_*_** from jdbc_user"**;<br />        ResultSet resultSet = statement.executeQuery**_(_**sql**_)_**; _//返回的结果为Reslut对象<br />    _**_}<br />__}_** |

| —- |

7. API使用: 5.处理结果集

查询结果会放到结果集中, 通过结果集获取查询的结果
04_JDBC:Java数据库连接技术 - 图16
04_JDBC:Java数据库连接技术 - 图17
1) 代码实现

| public class JdbcDemo1 {
_
_public static void
main(String[] args_) _throws ClassNotFoundException, SQLException {
__
//1.类加载 加载驱动
_Class._forName
(“com.mysql.cj.jdbc.Driver”);

    _//2 获取数据库连接<br />        _String url = **"jdbc:mysql://localhost:3306/bjsxt04**<br />**?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai"**;<br />        Connection connection = DriverManager._getConnection_**_(_**url,**"root"**,**"root"_)_**;

    _//3.获取SQL语句执行对象<br />        _Statement statement = connection.createStatement**_()_**;

    _//4.执行SQL语句, 并拿到返回结果<br />        _String sql = **"select **_*_** from jdbc_user"**;<br />        ResultSet rs = statement.executeQuery**_(_**sql**_)_**; _//返回的结果为查询到的数据(结果集)

    //5.处理结果集<br />        _**while _(_**rs.next**_()){<br />__            _int **id = rs.getInt**_(_"id"_)_**;<br />            String name = rs.getString**_(_"username"_)_**;<br />            String password = rs.getString**_(_"password"_)_**;<br />            **int **age = rs.getInt**_(_"age"_)_**;<br />            System.**_out_**.println**_(_**id + **":" **+ name + **":" **+ password + **":" **+ age**_)_**;<br />        **_}<br />__    }<br />__}_** |

| —- |

8. API使用: 6.资源的释放

·需要释放的对象:ResultSet结果集,Statement语句,Connection连接
ResultSet结果集: 当它的 Statement 关闭、重新执行或用于从多结果序列中获取下一个结果时,该ResultSet将被自动关闭
·释放原则: 先开的后关, 后开的先关 Statement ==> Connection

  1. 代码实现 | public class JdbcDemo1 {
    _
    _public static void
    main(String[] args_) _throws ClassNotFoundException, SQLException {
    __
    //1.类加载 加载驱动
    _Class._forName
    (“com.mysql.cj.jdbc.Driver”);
    //2 获取数据库连接
    _String url = “jdbc:mysql://localhost:3306/bjsxt04
    ?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai”;
    Connection connection = DriverManager._getConnection
    (url,“root”,“root”);
    //3.获取SQL语句执行对象
    _Statement statement = connection.createStatement**
    ()**;
    //4.执行SQL语句, 并拿到返回结果
    String sql = “select from jdbc_user”;
    ResultSet rs = statement.executeQuery**
    (sql)**; //5.处理结果
    **while (rs.next()){
    int id = rs.getInt(“id”);
    String name = rs.getString
    (“username”);
    String password = rs.getString
    (“password”);
    int age = rs.getInt
    (“age”);
    System.
    _out
    .println(id + “:” + name + “:” + password + “:” + age);
    _}
    **//6. 释放资源
    statement.close**();
    connection.close
    ();
    }
    _}*
    | | —- |

9. API使用总结

04_JDBC:Java数据库连接技术 - 图18
JDBC操作步骤的总结:

  1. 加载驱动(可以省略)
  2. 获取连接
  3. 创建SQL执行器
  4. 发送SQL并执行, 拿到返回结果集
  5. 处理结果集(查询需要)
  6. 资源的释放

    三. JDBC实现增删改

    1. 插入记录

    代码实现
public class JdbcDemo2 {
_
_public static void
main(String[] args_) _throws ClassNotFoundException, SQLException {
__
//1.加载驱动(注册驱动)
_Class._forName
(“com.mysql.cj.jdbc.Driver”);
//2.获取连接
_String url = “jdbc:mysql://localhost:3306/bjsxt04
?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai”; Connection connection = DriverManager._getConnection
(url, “root”, “root”);//3.创建SQL执行器_Statement statement = connection.createStatement**()**;//4.执行SQL, 并拿到返回值(增删改返回影响的行数)String sql = **”insert into jdbc_user values(default, ‘zl’, ‘444444’, 25 );int i = statement.executeUpdate(sql);System._out.println(“添加了”+i+“条数据”);_//5.释放资源_statement.close();connection.close();
}
}**

2. 变更记录

代码实现

public class JdbcDemo3 {
_
_public static void
main(String[] args_) _throws ClassNotFoundException, SQLException {
__
//1.加载驱动(注册驱动)
_Class._forName
(“com.mysql.cj.jdbc.Driver”);
//2.获取连接
_String url = “jdbc:mysql://localhost:3306/bjsxt04
?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai”;
Connection connection = DriverManager._getConnection
(url, “root”, “root”);
//3.创建SQL执行器
_Statement statement = connection.createStatement**
()**;
//4.执行SQL, 并拿到返回值(增删改返回影响的行数)
String sql = “update jdbc_user set password = ‘123456’ where id = 4”;
int i = statement.executeUpdate**
(sql);
System.
_out
.println(“变更了”+i+“条数据”);
_//5.释放资源
_statement.close
();
connection.close
();
}
__}
**

3. 删除记录

代码实现

public class JdbcDemo4 {
_
_public static void
main(String[] args_) _throws ClassNotFoundException, SQLException {
__
//1.加载驱动(注册驱动)
_Class._forName
(“com.mysql.cj.jdbc.Driver”);
//2.获取连接
_String url = “jdbc:mysql://localhost:3306/bjsxt04
?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai”;
Connection connection = DriverManager._getConnection
(url, “root”, “root”);
//3.创建SQL执行器
_Statement statement = connection.createStatement**
()**;
//4.执行SQL, 并拿到返回值(增伤改返回影响的行数)
String sql = “delete from jdbc_user where id = 4”;
int i = statement.executeUpdate**
(sql);
System.
_out
.println(“删除了”+i+“条数据”);
_//5.释放资源
_statement.close
();
connection.close
();
}
__}
**

四. 用户登录功能

1. 登录功能的实现

·需求
用户在控制台上输入用户名和密码, 显示 欢迎xxx登陆成功 或 登录失败
·实现思路
1) 获取用户从控制台上输入的用户名和密码来查询数据库
2) JDBC查询操作的6步
3) 根据用户名和密码查询,
·查询到记录(该用户存在), 登陆成功
·查询不到记录(该用户不存在), 登陆失败
代码实现

public class JdbcDemo5 {
_
_public static void
main(String[] args){
__
System.out.println(“欢迎登录的我系统”);
Scanner sc = new Scanner(System.in);
System.out.println(“请输入用户名”);
String name = sc.next();
System.out.println(“请输入密码”);
String pwd = sc.next();
Connection connection = null;
Statement statement = null;
//1.加载驱动(注册驱动)
try {
__
Class.forName(“com.mysql.cj.jdbc.Driver”);
//2.获取连接
_String url = “jdbc:mysql://localhost:3306/bjsxt04
?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai”;
connection = DriverManager._getConnection
(url, “root”, “root”);
//3.创建SQL执行器
_statement = connection.createStatement**
()**;
//4.执行SQL, 并拿到结果集
String sql = “select from jdbc_user where username=’”+name+“‘ and password=’”+pwd+“‘;”;
System.**_out
.println(sql);
ResultSet rs = statement.executeQuery
(sql);
//5.处理结果集
if(rs.next()){
__
String username = rs.getString(“username”);
System.
out.println(“欢迎: “ + username + “登陆成功”);
}_else {
System._out.println(“登录失败”);
_}
} catch (Exception e) {
e.printStackTrace();
}finally {
**//5.释放资源
**try {
statement.close();
connection.close
();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
_}*

04_JDBC:Java数据库连接技术 - 图192. 问题分析

1) 存在的问题?
我们让用户输入的密码和 SQL 语句进行字符串拼接。用户输入的内容作为了 SQL 语句语法的一部分,但是改变了原有 SQL真正的意义,以上问题称为SQL注入
SQL注入: 输入的内容作为sql执行一部分, 改变了原有sql的真正含义
2) 如何解决SQL注入的风险?
要解决SQL注入就不能让用户输入的密码和SQL 语句进行简单的手动字符串拼接

五. PreparedStatement预处理对象

1. PreparedStatement接口介绍

·PreparedStatement 是Statement 接口的子接口,继承于父接口中所有的方法。
它是一个预编译的 SQL 语句对象
·预编译:
是指SQL 语句被预编译, 并存储在PreparedStatement 对象中。然后可以使用此对象多次高效地执行该语句

2. PreparedStatement特点

·因为有预先编译的功能,提高SQL的执行效率
·可以有效的防止SQL 注入的问题,安全性更高

3. 获取PreparedStatement对象

04_JDBC:Java数据库连接技术 - 图20·通过Connection创建PreparedStatement对象

3.1 PreparedStatement常用方法

04_JDBC:Java数据库连接技术 - 图21

3.2 如何使用PreparedStatement

1) 编写SQL语句, 未知内容使用 ? 占位

String sql = “select* from jdbc_user where username=? and password=?”;
  1. 获取PreparedStatement对象
  2. 设置实际参数: setXxx(占位符的位置, 真实的值)
  3. 04_JDBC:Java数据库连接技术 - 图22执行SQL

    3.3 使用PreparedStatement完成登录功能

    | public class JdbcDemo6 {
    _
    _public static void
    main(String[] args){
    __
    System.out.println(“欢迎登录的我系统”);
    Scanner sc = new Scanner(System.in);
    System.out.println(“请输入用户名”);
    String name = sc.next();
    System.out.println(“请输入密码”);
    String pwd = sc.next();
    Connection connection = null;
    PreparedStatement ps = null;
    //1.加载驱动(注册驱动)
    try {
    __
    Class.forName(“com.mysql.cj.jdbc.Driver”);
    //2.获取连接
    _String url = “jdbc:mysql://localhost:3306/bjsxt04
    ?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai”;
    connection = DriverManager._getConnection
    (url, “root”, “root”);
    //3.创建SQL执行器
    _String sql = “select
    from jdbc_user where username=? and password=?;”;
    ps.setString**
    (1, name);
    ps.setString
    (2, pwd);
    System.
    _out
    .println(sql);
    ps = connection.prepareStatement
    (sql);
    _//4.执行SQL, 并拿到结果集
    _ResultSet rs = ps.executeQuery
    ();
    //5.处理结果集
    if(rs.next()){
    __
    String username = rs.getString(“username”);
    System.
    out.println(“欢迎: “ + username + “登陆成功”);
    }_else {
    System._out.println(“登录失败”);
    _}
    } catch (Exception e) {
    e.printStackTrace();
    }finally {
    **//5.释放资源
    **try {
    ps.close();
    connection.close
    ();
    } catch (SQLException throwables) {
    throwables.printStackTrace();
    }
    }
    }
    _}*
    | | —- |

3.4 PreparedStatement执行原理

·分别使用 Statement对象 和 PreparedStatement对象进行插入操作
代码实现

| public class JdbcDemo7 {
_
_public static void
main(String[] args_) _throws ClassNotFoundException, SQLException {
__
Class.forName(“com.mysql.cj.jdbc.Driver”);
String url = “jdbc:mysql://localhost:3306/bjsxt04
?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai”;
Connection connection = DriverManager.getConnection(url, “root”, “root”);
//获取Statement _Statement st = connection.createStatement**();
st.executeUpdate
(“insert into jdbc_user values(null, ‘张四’, ‘111’, 11 ))**; //执行添加 st.executeUpdate**(“insert into jdbc_user values(null, ‘张五’, ‘111’, 22 ))**; //执行添加_

//获取PreparedStatement _String sql = **”insert into jdbc_user values(default, ?, ?, ?);
PreparedStatement ps = connection.prepareStatement
(sql);
ps.setString
(1,“赵七”);
ps.setString
(2,“111”);
ps.setInt
(3,28);
ps.executeUpdate
()**; //执行添加
ps.setString**
(1,“赵八”);
ps.setString
(2,“222”);
ps.setInt
(3,38);
ps.executeUpdate
()**; //执行添加
st.close**
();
ps.close
();
connection.close
();
}
_}** | | —- |

04_JDBC:Java数据库连接技术 - 图23
04_JDBC:Java数据库连接技术 - 图24扩展:当客户端发送一条SQL语句给DBMS时,MySQL的执行流程如上图

  1. 客户端向服务器端发送SQL命令
  2. 服务器端连接模块连接并验证
  3. 缓存模块解析SQL为Hash并与缓存中Hash表对应。如果有结果直接返回结果,如果没有对应继续向下执行
  4. 解析器解析SQL为解析树,如出现错误, 报SQL解析错误。如果正确,向下传递
  5. 预处理器对解析树继续处理,处理成新的解析树。
  6. 优化器根据开销自动选择最优执行计划,生成执行计划
  7. 执行器执行执行计划,访问存储引擎接口
  8. 存储引擎访问物理文件并返回结果
  9. 如果开启缓存,缓存管理器把结果放入到查询缓存中。
  10. 返回结果给客户端

    3.5 PreparedStatement批量添加

    代码实现

| public class JdbcDemo8 {
_
_public static void
main(String[] args_) _throws ClassNotFoundException, SQLException {
__
//1.加载驱动(注册驱动)
_Class._forName
(“com.mysql.cj.jdbc.Driver”);
//2.获取连接
_String url = “jdbc:mysql://localhost:3306/bjsxt04
?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai”;
Connection connection = DriverManager._getConnection
(url, “root”, “root”);
//3.创建SQL执行器
_String sql = **”insert into jdbc_user values
(null, ?, ?, ?);
PreparedStatement ps = connection.prepareStatement
(sql);
ps.setString
(1,“张十一”);
ps.setString
(2,“111”);
ps.setInt
(3,28);
ps.addBatch
()_**; //添加到批量操作

    ps.setString**_(_**1,**"张十二"_)_**;<br />        ps.setString**_(_**2,**"111"_)_**;<br />        ps.setInt**_(_**3,28**_)_**;<br />        ps.addBatch**_()_**; //添加到批量操作

    ps.setString**_(_**1,**"张十三"_)_**;<br />        ps.setString**_(_**2,**"111"_)_**;<br />        ps.setInt**_(_**3,28**_)_**;<br />        ps.addBatch**_()_**; //添加到批量操作

    _//4.执行批量操作, 获取批量操作的添加行数<br />        _**int_[] _**ints = ps.executeBatch**_()_**;<br />        System.**_out_**.println**_(_**Arrays._toString_**_(_**ints**_))_**;<br />        _//5.释放资源<br />        _ps.close**_()_**;<br />        connection.close**_()_**;<br />    **_}<br />__}_** |

| —- |

JDBC提供的批处理功能(Batch)。关键点如下:
1) 批处理是指将关联的SQL语句组合成一个批处理,并将他们当成一次调用提交给数据库, 一次发送多个SQL语句到数据库,可以减少通信的资源消耗,从而提高了性能
2) executeBatch() 方法用于启动执行所有组合在一起的语句。
3) executeBatch() 方法返回一个整数数组,数组中的每个元素代表了各自的影响行数

04_JDBC:Java数据库连接技术 - 图2504_JDBC:Java数据库连接技术 - 图26
3.6 PreparedStatement获取自增主键值

代码实现

public class JdbcDemo9 {
_
_public static void
main(String[] args_) _throws ClassNotFoundException, SQLException {
__
//1.加载驱动(注册驱动)
_Class._forName
(“com.mysql.cj.jdbc.Driver”);
//2.获取连接
_String url = “jdbc:mysql://localhost:3306/bjsxt04
?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai”;
Connection connection = DriverManager._getConnection
(url, “root”, “root”);
//3.创建SQL执行器
_String sql = **”insert into jdbc_user values
(null, ?, ?, ?);
PreparedStatement ps = connection.prepareStatement
(sql, Statement._RETURN_GENERATED_KEYS); //返回自增的值
ps.setString
(1,“张十四”);
ps.setString
(2,“111”);
ps.setInt
(3,28);
_//4.执行SQL
_ps.executeUpdate
();
_//5.获取自增主键值
_ResultSet gk = ps.getGeneratedKeys
();
while (gk.next()){
__ _int i = gk.getInt
(1);
System.
_out
.println(i);
}
__
_//6.释放资源
_ps.close
();
connection.close
();
}
__}
**

六. JDBC事务控制

事务是一个整体, 由一条或者多条SQL语句组成, 这些SQL语句要么都执行成功, 要么就失败, 只要有一条SQL出现异常, 整个操作就会回滚
回滚: 就是事务运行的过程中发生了某种故障, 或者SQL出现了异常, 事务不能继续执行, 系统将事务中对数据库的所有已完成的操作全部取消, 回滚到事务开始时的状态
宕机等情况自动回滚, 代码的bug手动回滚
事务控制的使用方式:
1) 使用MySQL的命令来操作事务控制
2) 使用JDBC操作事务控制

1. 事务相关API

04_JDBC:Java数据库连接技术 - 图27·使用connection中的方法实现事务控制

2. 使用事务控制实现转账

  1. 数据准备 | — 创建账户表
    create table account(
    id int primary key auto_increment, — 主键
    name varchar(10), — 姓名
    money double — 余额
    );
    — 添加两个账户
    insert into account (name, money) values (‘tom’, 1000), (‘jack’, 1000); | | —- |

2) 思路分析
1. 加载驱动(可以省略)
2. 获取连接
3. 开启事务控制
4. 获取SQL执行器(PreparedStatement对象)
5. 执行SQL
6. 没出现异常, 事务提交
7. 出现异常, 事务回滚
8. 释放资源
3)代码实现

public class JdbcDemo10 {
_
_public static void
main(String[] args) {
__
Connection connection = null;
PreparedStatement ps =null;
try {
__
//1.加载驱动(注册驱动)
_Class._forName
(“com.mysql.cj.jdbc.Driver”);
//2.获取连接
_String url = “jdbc:mysql://localhost:3306/bjsxt04
?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai”;
connection = DriverManager._getConnection
(url, “root”, “root”);
//3.开启事务
_connection.setAutoCommit**
(false)**;
//4.创建SQL执行器
String sql = “update account set money = money + ? where id = ?”;
ps = connection.prepareStatement**
(sql);
ps.setDouble
(1, -500)**; // tom 转走500
ps.setInt**(2, 1);
ps.executeUpdate
()**; //5.执行
//int i = 1/0;
ps.setDouble**(1, 500)**;// jack 转入500
ps.setInt**(2, 2);
ps.executeUpdate
()**; //5.执行
//6.没出现异常, 事务提交
connection.commit**();
} catch (Exception e) {
e.printStackTrace();
try
{
**//7.出现异常, 事务回滚
connection.close**();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}finally {
try {
**//8.释放资源
ps.close**();
connection.close
();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}_**

七. 连接池

1. 连接池引入:

对于一个简单的应用程序,由于对于数据库的访问不是很频繁。 这时可以简单地在需要访问数据库时,就新创建一个连接,用完后就关闭它,这样做也不会带来什么明显的性能上的开销。
但是对于一个复杂的数据库应用,情况就完全不同了。频繁的建立、关闭连接,会极大的减低系统的性能,因为对于连接的使用成了系统性能的瓶颈

2. 连接池原理

数据库连接池的基本原理是连接池对象中维护一定数量的数据库连接, 并对外暴露数据库连接获取和返回方法
例如:
外部使用者可通过getConnection 方法获取连接,使用完毕后再通closeConnection方法将连接返回,注意此时连接并没有关闭,而是放回连接池,并为下一次使用做好准备**04_JDBC:Java数据库连接技术 - 图28

3. 手写连接池

代码实现

public class ConnectionUtils {
__
//使用LinkedList集合作为连接池, 获取连接和返回连接相当于移除和添加的操作
private static LinkedList<Connection> list = new LinkedList<>();;
//只在第一次创建ConnectionUtils对象时, 创建连接池
static {
__ _try
{
_
//1.类加载 加载驱动
_Class._forName
(“com.mysql.cj.jdbc.Driver”);
//2 获取数据库连接
_String url = “jdbc:mysql://localhost:3306/bjsxt04
?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai”;
//3. 向连接池中放入10个连接
**for (int i = 0; i < 10; i++) {
**Connection connection = DriverManager._getConnection(url,“root”,“root”);
list.add(connection);
**_}
} catch (Exception e) {
e.printStackTrace();
}
}
**//从连接池中获取连接
public synchronized Connection getConnection**(){
**//需要判断连接池中是否存在连接
**if(**_list.size() == 0){
__
//连接池中没有连接, 需要等待, 其他用户释放连接
try {
__
//释放锁, 进入等待
this.wait();
} _catch (_InterruptedException e) {
__
e.printStackTrace();
}
}
//连接池中还有连接, 返回连接池中取出的连接
_Connection connection = _list
.remove(0);
return connection;
}
__
//将连接放回连接池中
public synchronized void closeConnection(Connection connection){
__
list.add(connection);
//唤醒所有等待
this.notifyAll();
}
__}