目录
1 Connection中的重用方法
2 JDBC事务管理经典案例
1 Connection类中常用的方法回顾
1.1 Statement createStatement() throws SQLException;
创建一个Statement实例(即:创建一个SQL执行对象)
1.2 PreparedStatement prepareStatement(String sql) throws SQLException;
创建一个PreparedStatement对象(即:创建一个预编译SQL执行对象)
1.3 void setAutoCommit(boolean autoCommit) throws SQLException;
设置事务的自动提交(false为关闭自动提交,true为启动自动提交)
1.4 void commit() throws SQLException;
手动提交事务
1.5 void rollback() throws SQLException;
手动回滚事务
2 需要用到事务回滚的经典案例:银行转账案例
转出和转入是一个事务,如果转出成功但是转入失败的会就需要进行事务回滚,否则就出出现转出者余额减少但是转入者余额没有增加
通过Connection提供的方法来调用的;本质上事务还是依赖数据库的实现;Connection的方法实质上也是调用了数据库事务机制.
2.1 不使用事务控制的转账业务
缺点:如果转入成功,但是转入失败的话,会造成转出者余额减少,但是转入者余额不变
项目结构图
1 package cn.xiangxu.entity;
2
3 import java.sql.Connection;
4 import java.sql.PreparedStatement;
5 import java.util.Scanner;
6
7 import cn.xiangxu.tools.DBUtil;
8
9 public class Test {
10 public static void main(String[] args) {
11 Scanner scanner = new Scanner(System.in);
12 System.out.println("请输入转出用户名:");
13 String outName = scanner.nextLine();
14 System.out.println("请输入需要转出的资金额度:");
15 Double money = Double.parseDouble(scanner.nextLine());
16 System.out.println("请输入转入用户名:");
17 String inName = scanner.nextLine();
18 System.out.println("转出账户为:" + outName + "转出金额为:" + money + "转入账户为:" + inName);
19
20
21 Connection conn = null;
22 try {
23 conn = DBUtil.getConnection(); // 实例化连接对象
24
25 // conn.setAutoCommit(false); // 关闭自动提交事务功能
26
27 String sql = "UPDATE client "
28 + "SET account = account - ? "
29 + "WHERE name = ? ";
30 PreparedStatement ps = conn.prepareStatement(sql);
31 ps.setDouble(1, money);
32 ps.setString(2, outName);
33 Integer rs = ps.executeUpdate();
34 if(rs > 0) {
35 System.out.println("转出成功");
36 } else {
37 System.out.println("转出失败");
38 return; // 转出失败跳出函数,不再执行下面的语句;但是finally中的语句还是会执行的,因为就算天塌下来finally中的语句都会执行
39 }
40
41 System.out.println("======分割线=======");
42
43 String sql_in = "UPDATE client "
44 + "SET account = account + ? "
45 + "WHERE name = ? ";
46 PreparedStatement ps_in = conn.prepareStatement(sql_in);
47 ps_in.setDouble(1, money);
48 ps_in.setString(2, inName);
49 Integer judge_in = ps_in.executeUpdate();
50 if(judge_in > 0) {
51 System.out.println("转入成功");
52 // conn.commit(); // 转出、转入都成功就提交事务
53 } else {
54 System.out.println("转入失败");
55 // conn.rollback(); // 转出成功、转入失败就回滚事务
56 }
57
58 // conn.setAutoCommit(true); // 打开自动提交事务
59
60 } catch (Exception e) {
61 // TODO Auto-generated catch block
62 e.printStackTrace();
63 } finally {
64 System.out.println("我是finally中的语句哟");
65 try {
66 DBUtil.closeConnection();
67 } catch (Exception e) {
68 // TODO Auto-generated catch block
69 e.printStackTrace();
70 }
71 }
72 }
73 }
转账业务java源代码
1 CREATE TABLE client (
2 id INT (10) PRIMARY KEY,
3 name VARCHAR (10),
4 pwd VARCHAR (10),
5 account INT (20)
6 );
SQL语句
1 package cn.xiangxu.tools;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.sql.Connection;
6 import java.sql.SQLException;
7 import java.util.Properties;
8
9 import org.apache.commons.dbcp.BasicDataSource;
10
11 public class DBUtil {
12 /*
13 * ThreadLocal用于线程跨方法共享数据使用
14 * ThreadLocal内部有一个Map, key为需要共享数据的线程本身,value就是其需要共享的数据
15 */
16 private static ThreadLocal<Connection> tl; // 声明一个类似于仓库的东西
17 private static BasicDataSource dataSource; // 声明一个数据库连接池对象
18
19 // 静态代码块,在类加载的时候执行,而且只执行一次
20 static {
21 tl = new ThreadLocal<Connection>(); // 实例化仓库对象
22 dataSource = new BasicDataSource(); // 实例数据库连接池对象
23
24 Properties prop = new Properties(); // 创建一个Properties对象用(该对象可以用来加载配置文件中的属性列表)
25 InputStream is = DBUtil.class.getClassLoader().getResourceAsStream("config/mysql.properties"); // 读取配置文件信息
26 try {
27 prop.load(is); // 加载配置文件中的属性列表
28
29 String driverClassName = prop.getProperty("driverClassName"); // 获取属性信息
30 String url = prop.getProperty("url");
31 String username = prop.getProperty("username");
32 String password = prop.getProperty("password");
33 Integer maxActive = Integer.parseInt(prop.getProperty("maxActive"));
34 Integer maxWait = Integer.parseInt(prop.getProperty("maxWait"));
35
36 dataSource.setDriverClassName(driverClassName); // 初始化数据库连接池(即:配置数据库连接池的先关参数)
37 dataSource.setUrl(url);
38 dataSource.setUsername(username);
39 dataSource.setPassword(password);
40 dataSource.setMaxActive(maxActive);
41 dataSource.setMaxWait(maxWait);
42
43 is.close(); // 关闭输入流,释放资源
44 } catch (IOException e) {
45 // TODO Auto-generated catch block
46 e.printStackTrace();
47 }
48
49 }
50
51 /**
52 * 创建连接对象(注意:静态方法可以直接通过类名来调用)
53 * @return 连接对象
54 * @throws Exception
55 */
56 public static Connection getConnection() throws Exception {
57 try {
58 Connection conn = dataSource.getConnection(); // 创建连接对象(利用数据库连接池进行创建)
59 tl.set(conn); // 将连接对象放到仓库中
60 return conn;
61 } catch (Exception e) {
62 // TODO Auto-generated catch block
63 e.printStackTrace();
64 throw e;
65 }
66 }
67
68 /**
69 * 关闭连接对象(注意:静态方法可以通过类名直接调用)
70 * @throws Exception
71 */
72 public static void closeConnection() throws Exception {
73 Connection conn = tl.get(); // 从仓库中取出连接对象
74 tl.remove(); // 清空仓库
75 if(conn != null) { // 判断连接对象是否释放资源
76 try {
77 conn.close();
78 } catch (Exception e) {
79 // TODO Auto-generated catch block
80 e.printStackTrace();
81 throw e;
82 }
83 }
84 }
85
86 }
数据库连接池的java源代码
1 # zhe shi zhu shi , yi ban bu yong zhong wen
2 # deng hao liang bian mei you kong ge, mo wei mei you fen hao
3 # hou mian bu neng you kong ge
4 driverClassName=com.mysql.jdbc.Driver
5 url=jdbc:mysql://localhost:3306/test
6 username=root
7 password=182838
8 maxActive=100
9 maxWait=3000
数据库信息文件
1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2 <modelVersion>4.0.0</modelVersion>
3 <groupId>cn.xiangxu</groupId>
4 <artifactId>testJDBC</artifactId>
5 <version>0.0.1-SNAPSHOT</version>
6 <dependencies>
7 <dependency>
8 <groupId>mysql</groupId>
9 <artifactId>mysql-connector-java</artifactId>
10 <version>5.1.37</version>
11 </dependency>
12 <dependency>
13 <groupId>junit</groupId>
14 <artifactId>junit</artifactId>
15 <version>4.12</version>
16 </dependency>
17 <dependency>
18 <groupId>commons-dbcp</groupId>
19 <artifactId>commons-dbcp</artifactId>
20 <version>1.4</version>
21 </dependency>
22 </dependencies>
23 </project>
maven依赖文件
2.2 利用事务控制的转账业务
1 package cn.xiangxu.entity;
2
3 import java.sql.Connection;
4 import java.sql.PreparedStatement;
5 import java.sql.SQLException;
6 import java.util.Scanner;
7
8 import cn.xiangxu.tools.DBUtil;
9
10 public class Test {
11 public static void main(String[] args) {
12 Scanner scanner = new Scanner(System.in);
13 System.out.println("请输入转出用户名:");
14 String outName = scanner.nextLine();
15 System.out.println("请输入需要转出的资金额度:");
16 Double money = Double.parseDouble(scanner.nextLine());
17 System.out.println("请输入转入用户名:");
18 String inName = scanner.nextLine();
19 System.out.println("转出账户为:" + outName + "转出金额为:" + money + "转入账户为:" + inName);
20
21
22 Connection conn = null;
23 try {
24 conn = DBUtil.getConnection(); // 实例化连接对象
25
26 conn.setAutoCommit(false); // 关闭自动提交事务功能
27
28 String sql = "UPDATE client "
29 + "SET account = account - ? "
30 + "WHERE name = ? ";
31 PreparedStatement ps = conn.prepareStatement(sql);
32 ps.setDouble(1, money);
33 ps.setString(2, outName);
34 Integer rs = ps.executeUpdate();
35 if(rs > 0) {
36 System.out.println("转出成功");
37 } else {
38 System.out.println("转出失败");
39 return; // 转出失败跳出函数,不再执行下面的语句;但是finally中的语句还是会执行的,因为就算天塌下来finally中的语句都会执行
40 }
41
42 System.out.println("======分割线=======");
43
44 String sql_in = "UPDATE client "
45 + "SET account = account + ? "
46 + "WHERE name = ? ";
47 PreparedStatement ps_in = conn.prepareStatement(sql_in);
48 ps_in.setDouble(1, money);
49 ps_in.setString(2, inName);
50 Integer judge_in = ps_in.executeUpdate();
51 if(judge_in > 0) {
52 System.out.println("转入成功");
53 conn.commit(); // 转出、转入都成功就提交事务
54 } else {
55 System.out.println("转入失败");
56 conn.rollback(); // 转出成功、转入失败就回滚事务
57 }
58
59 conn.setAutoCommit(true); // 打开自动提交事务
60
61 } catch (Exception e) {
62 // TODO Auto-generated catch block
63 try {
64 conn.rollback(); // 捕获到异常后也需要进行事务回滚
65 } catch (SQLException e1) {
66 // TODO Auto-generated catch block
67 e1.printStackTrace();
68 }
69 e.printStackTrace();
70 } finally {
71 System.out.println("我是finally中的语句哟");
72 try {
73 DBUtil.closeConnection();
74 } catch (Exception e) {
75 // TODO Auto-generated catch block
76 e.printStackTrace();
77 }
78 }
79 }
80 }
转账业务的java源代码
2.3 将关闭自动提交功能、手动提交功能、手动回滚功能封装到一个类中
1 package cn.xiangxu.tools;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.sql.Connection;
6 import java.sql.SQLException;
7 import java.util.Properties;
8
9 import org.apache.commons.dbcp.BasicDataSource;
10
11 public class DBUtil {
12 /*
13 * ThreadLocal用于线程跨方法共享数据使用
14 * ThreadLocal内部有一个Map, key为需要共享数据的线程本身,value就是其需要共享的数据
15 */
16 private static ThreadLocal<Connection> tl; // 声明一个类似于仓库的东西
17 private static BasicDataSource dataSource; // 声明一个数据库连接池对象
18
19 // 静态代码块,在类加载的时候执行,而且只执行一次
20 static {
21 tl = new ThreadLocal<Connection>(); // 实例化仓库对象
22 dataSource = new BasicDataSource(); // 实例数据库连接池对象
23
24 Properties prop = new Properties(); // 创建一个Properties对象用(该对象可以用来加载配置文件中的属性列表)
25 InputStream is = DBUtil.class.getClassLoader().getResourceAsStream("config/mysql.properties"); // 读取配置文件信息
26 try {
27 prop.load(is); // 加载配置文件中的属性列表
28
29 String driverClassName = prop.getProperty("driverClassName"); // 获取属性信息
30 String url = prop.getProperty("url");
31 String username = prop.getProperty("username");
32 String password = prop.getProperty("password");
33 Integer maxActive = Integer.parseInt(prop.getProperty("maxActive"));
34 Integer maxWait = Integer.parseInt(prop.getProperty("maxWait"));
35
36 dataSource.setDriverClassName(driverClassName); // 初始化数据库连接池(即:配置数据库连接池的先关参数)
37 dataSource.setUrl(url);
38 dataSource.setUsername(username);
39 dataSource.setPassword(password);
40 dataSource.setMaxActive(maxActive);
41 dataSource.setMaxWait(maxWait);
42
43 is.close(); // 关闭输入流,释放资源
44 } catch (IOException e) {
45 // TODO Auto-generated catch block
46 e.printStackTrace();
47 }
48
49 }
50
51 /**
52 * 创建连接对象(注意:静态方法可以直接通过类名来调用)
53 * @return 连接对象
54 * @throws Exception
55 */
56 public static Connection getConnection() throws Exception {
57 try {
58 Connection conn = dataSource.getConnection(); // 创建连接对象(利用数据库连接池进行创建)
59 tl.set(conn); // 将连接对象放到仓库中
60 return conn;
61 } catch (Exception e) {
62 // TODO Auto-generated catch block
63 e.printStackTrace();
64 throw e;
65 }
66 }
67
68 /**
69 * 关闭连接对象(注意:静态方法可以通过类名直接调用)
70 * @throws Exception
71 */
72 public static void closeConnection() throws Exception {
73 Connection conn = tl.get(); // 从仓库中取出连接对象
74 tl.remove(); // 清空仓库
75 if(conn != null) { // 判断连接对象是否释放资源
76 try {
77 conn.close();
78 } catch (Exception e) {
79 // TODO Auto-generated catch block
80 e.printStackTrace();
81 throw e;
82 }
83 }
84 }
85
86 /**
87 * 在执行SQL语句前关闭JDBC的自动提交事务功能
88 * @throws SQLException
89 */
90 public static void tansBegin() throws SQLException {
91 try {
92 tl.get().setAutoCommit(false); // 从仓库中获取连接对象并调用setAutoCommit来关闭自动提交事务功能
93 } catch(SQLException e) {
94 e.printStackTrace();
95 throw e;
96 }
97 }
98
99 /**
100 * 手动回滚功能
101 * @throws SQLException
102 */
103 public static void transBack() throws SQLException {
104 tl.get().rollback(); // 从仓库中获取连接对象并调用rollback来实现事务回滚操作
105 tl.get().setAutoCommit(true); // 回滚启动事务自动提交功能
106 }
107
108 /**
109 * 手动提交功能
110 * @throws SQLException
111 */
112 public static void transCommit() throws SQLException {
113 tl.get().commit(); // 从仓库中获取连接对象并调用commit来实现事务提交操作
114 tl.get().setAutoCommit(true); // 提交后启动事务自动提交功能
115 }
116
117 }
DBUtil
1 package cn.xiangxu.entity;
2
3 import java.sql.Connection;
4 import java.sql.PreparedStatement;
5 import java.sql.SQLException;
6 import java.util.Scanner;
7
8 import cn.xiangxu.tools.DBUtil;
9
10 public class Test {
11 public static void main(String[] args) {
12 Scanner scanner = new Scanner(System.in);
13 System.out.println("请输入转出用户名:");
14 String outName = scanner.nextLine();
15 System.out.println("请输入需要转出的资金额度:");
16 Double money = Double.parseDouble(scanner.nextLine());
17 System.out.println("请输入转入用户名:");
18 String inName = scanner.nextLine();
19 System.out.println("转出账户为:" + outName + "转出金额为:" + money + "转入账户为:" + inName);
20
21
22 Connection conn = null;
23 try {
24 conn = DBUtil.getConnection(); // 实例化连接对象
25
26 DBUtil.tansBegin(); // 关闭自动提交事务功能
27
28 String sql = "UPDATE client "
29 + "SET account = account - ? "
30 + "WHERE name = ? ";
31 PreparedStatement ps = conn.prepareStatement(sql);
32 ps.setDouble(1, money);
33 ps.setString(2, outName);
34 Integer rs = ps.executeUpdate();
35 if(rs > 0) {
36 System.out.println("转出成功");
37 } else {
38 System.out.println("转出失败");
39 return; // 转出失败跳出函数,不再执行下面的语句;但是finally中的语句还是会执行的,因为就算天塌下来finally中的语句都会执行
40 }
41
42 System.out.println("======分割线=======");
43
44 String sql_in = "UPDATE client "
45 + "SET account = account + ? "
46 + "WHERE name = ? ";
47 PreparedStatement ps_in = conn.prepareStatement(sql_in);
48 ps_in.setDouble(1, money);
49 ps_in.setString(2, inName);
50 Integer judge_in = ps_in.executeUpdate();
51 if(judge_in > 0) {
52 System.out.println("转入成功");
53 DBUtil.transCommit(); // 转出、转入都成功就提交事务
54 } else {
55 System.out.println("转入失败");
56 DBUtil.transBack(); // 转出成功、转入失败就回滚事务
57 }
58
59 } catch (Exception e) {
60 // TODO Auto-generated catch block
61 try {
62 DBUtil.transBack();// 捕获到异常后也需要进行事务回滚
63 } catch (SQLException e1) {
64 // TODO Auto-generated catch block
65 e1.printStackTrace();
66 }
67 e.printStackTrace();
68 } finally {
69 System.out.println("我是finally中的语句哟");
70 try {
71 DBUtil.closeConnection();
72 } catch (Exception e) {
73 // TODO Auto-generated catch block
74 e.printStackTrace();
75 }
76 }
77 }
78 }
转账业务java源代码