MySQL数据库学习笔记(十)----JDBC事务处理、封装JDBC工具类

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介:

【正文】

首先需要回顾一下上一篇文章中的内容:MySQL数据库学习笔记(九)----JDBC的PreparedStatement接口重构增删改查

一、JDBC事务处理:

我们已经知道,事务的概念即:所有的操作要么同时成功,要么同时失败。在MySQL中提供了Commit、Rollback命令进行事务的提交与回滚。实际上在JDBC中也存在事务处理,如果要想进行事务处理的话,则必须按照以下的步骤完成。

JDBC中事务处理的步骤:

1、要取消掉JDBC的自动提交:void setAutoCommit(boolean autoCommit)

2、执行各个SQL语句,加入到批处理之中

3、如果所有语句执行成功,则提交事务 commit();如果出现了错误,则回滚:rollback()

核心代码:

复制代码
conn.setAutoCommit(false); // 取消自动提交
把SQL语句加入批处理
stmt.addBatch(…) ()
stmt.addBatch(…)
//执行批处理操作
stmt.executeBatch();
conn.commit(); // 提交事务

//如果发生错误
conn.rollback();
复制代码

代码举例:

首先在sql中创建一个空的数据库,现在在java中,使用PreparedStatement插入数据并修改数据。正常情况下,代码应该这样写:

复制代码
 1 package com.vae.jdbc;
 2 
 3 import java.sql.Connection;
 4 import java.sql.DriverManager;
 5 import java.sql.PreparedStatement;
 6 import java.sql.ResultSet;
 7 import java.sql.SQLException;
 8 
 9 public class JDBCtest {
10 
11 
12     //数据库连接地址
13     public final static String URL = "jdbc:mysql://localhost:3306/JDBCdb";
14     //用户名
15     public final static String USERNAME = "root";
16     //密码
17     public final static String PASSWORD = "smyh";
18     //驱动类
19     public final static String DRIVER = "com.mysql.jdbc.Driver";
20     
21     
22     public static void main(String[] args) {
23         // TODO Auto-generated method stub
24         //insert(p);
25         //update(p);
26         //delete(3);
27         insertAndQuery();
28     }
29     
30     
31     //方法:使用PreparedStatement插入数据、更新数据
32     public static void insertAndQuery(){
33         Connection conn = null;
34         try {
35             Class.forName(DRIVER);
36             conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
37             String sql1 = "insert into user(name,pwd)values(?,?)";
38             String sql2 = "update user set pwd=? where name=?";
39             PreparedStatement ps = conn.prepareStatement(sql1);
40             ps.setString(1, "smyhvae");
41             ps.setString(2, "007");            
42             ps.executeUpdate();
43             
44             ps = conn.prepareStatement(sql2);
45             ps.setString(1, "008");
46             ps.setString(2, "smyh");            
47             ps.executeUpdate();            
48             
49             ps.close();
50             conn.close();            
51             
52         } catch (ClassNotFoundException e) {
53             e.printStackTrace();
54         } catch (SQLException e) {
55             e.printStackTrace();
56         }
57     }
58     
59 }
复制代码

事务处理:

现在我们把上面的插入操作和修改操作变成一个事务,就要增加一部分代码了。修改上方的insertAndQuery()方法里面的代码:

复制代码
 1 //方法:使用PreparedStatement插入数据、更新数据
 2     public static void insertAndQuery(){
 3         Connection conn = null;
 4         try {
 5             Class.forName(DRIVER);
 6             conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
 7             conn.setAutoCommit(false);//设置为手动提交事务
 8             String sql1 = "insert into user(name,pwd)values(?,?)";
 9             String sql2 = "update user set pwd=? where name=?";
10             PreparedStatement ps = conn.prepareStatement(sql1);
11             ps.setString(1, "smyhvae");
12             ps.setString(2, "007");            
13             ps.executeUpdate();
14             
15             ps = conn.prepareStatement(sql2);
16             ps.setString(1, "008");
17             ps.setString(2, "smyh");            
18             ps.executeUpdate();            
19             conn.commit(); //如果所有sql语句成功,则提交事务
20             ps.close();
21             conn.close();
22             
23         } catch (ClassNotFoundException e) {
24             e.printStackTrace();
25         } catch (SQLException e) {
26             e.printStackTrace();
27             try {
28                 conn.rollback();//只要有一个sql语句出现错误,则将事务回滚 
29             } catch (SQLException e1) {
30                 e1.printStackTrace();
31             }
32         }
33         
34     }
复制代码

核心代码是第07行、19行、28行。这三行代码就完成了事务处理的操作。两个sql语句中,只要有一个语句出现错误,程序将无法运行,说明事务提交失败,且报错如下:

 

二、封装JDBC工具类

之前的JDBC代码分析:

我们可以先回顾一下上一篇博文中的第五段:使用PreparedStatement重构增删改查。

通过分析可以发现有以下不足:有许多重复的代码、每次都要加载驱动、获取连接等。增删改查无非只是slq语句不一样而已。

封装工具类就是一个抽象的过程,我们可以把现在代码中非常公用的代码抽取出来,形成一个工具类。

  • 第一步:抽象公共的代码到工具类。
  • 第二步:为提高可以连接不同数据库的能力,将连接数据库的URL、用户名,密码等信息编写在一个属性文件(jdbc.properties)中,方便以后进行修改。 

我们先把之前的文章中,使用PreparedStatement查询数据库的代码贴出来,方便和后面的内容进行对比,省的翻来翻去麻烦。

使用PreparedStatement查询数据库:(重构前)

在这之前,请建好一个Person类,参考上一篇博文就行了。然后,JDBCtest.java的代码如下:

复制代码
 1 package com.vae.jdbc;
 2 
 3 import java.sql.Connection;
 4 import java.sql.DriverManager;
 5 import java.sql.PreparedStatement;
 6 import java.sql.ResultSet;
 7 import java.sql.SQLException;
 8 
 9 public class JDBCtest {
10 
11 
12     //数据库连接地址
13     public final static String URL = "jdbc:mysql://localhost:3306/JDBCdb";
14     //用户名
15     public final static String USERNAME = "root";
16     //密码
17     public final static String PASSWORD = "smyh";
18     //驱动类
19     public final static String DRIVER = "com.mysql.jdbc.Driver";
20     
21     
22     public static void main(String[] args) {
23         // TODO Auto-generated method stub
24         Person p = new Person();
25 
26         p = findById(2);
27         System.out.println(p);
28     }   
29     
30  
31     
32     // 使用PreparedStatement查询数据
33     public static Person findById(int id){
34         Person p = null;
35         try {
36             Class.forName(DRIVER);
37             Connection conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
38             String sql = "select name,age,description from person where id=?";
39             PreparedStatement ps = conn.prepareStatement(sql);
40             //设置占位符对应的值
41             ps.setInt(1, id);
42             
43             ResultSet rs = ps.executeQuery();
44             if(rs.next()){
45                 p = new Person();
46                 p.setId(id);
47                 p.setName(rs.getString(1));
48                 p.setAge(rs.getInt(2));
49                 p.setDescription(rs.getString(3));
50                 
51             }
52             rs.close();
53             ps.close();
54             conn.close();
55             
56             
57         } catch (ClassNotFoundException e) {
58             e.printStackTrace();
59         } catch (SQLException e) {
60             e.printStackTrace();
61         }
62         return p;
63     }
64     
65 
66 }
复制代码

接下来开始真正的工作了,从零开始。

封装工具类:

新建工程文件,结构如下:

37ba68f4-fa7f-49fc-bfb5-1d6b4acc4c66

(1)先新建一个DBUtils工具类:

复制代码
 1 package com.vae.jdbc;
 2 
 3 import java.sql.Connection;
 4 import java.sql.DriverManager;
 5 import java.sql.ResultSet;
 6 import java.sql.SQLException;
 7 import java.sql.Statement;
 8 import java.util.ResourceBundle;
 9 
10 /**
11  * 数据库操作工具类
12  * @author lamp
13  *
14  */
15 public class DBUtils {
16     
17     //数据库连接地址
18     public static String URL;
19     //用户名
20     public static String USERNAME;
21     //密码
22     public static String PASSWORD;
23     //mysql的驱动类
24     public static String DRIVER;
25     
26     private static ResourceBundle rb = ResourceBundle.getBundle("com.vae.jdbc.db-config");
27     
28     private DBUtils(){}
29     
30     //使用静态块加载驱动程序
31     static{
32         URL = rb.getString("jdbc.url");
33         USERNAME = rb.getString("jdbc.username");
34         PASSWORD = rb.getString("jdbc.password");
35         DRIVER = rb.getString("jdbc.driver");
36         try {
37             Class.forName(DRIVER);
38         } catch (ClassNotFoundException e) {
39             e.printStackTrace();
40         }
41     }
42     //定义一个获取数据库连接的方法
43     public static Connection getConnection(){
44         Connection conn = null;
45         try {
46             conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
47         } catch (SQLException e) {
48             e.printStackTrace();
49             System.out.println("获取连接失败");
50         }
51         return conn;
52     }
53     
54     /**
55      * 关闭数据库连接
56      * @param rs
57      * @param stat
58      * @param conn
59      */
60     public static void close(ResultSet rs,Statement stat,Connection conn){
61             try {
62                 if(rs!=null)rs.close();
63                 if(stat!=null)stat.close();
64                 if(conn!=null)conn.close();
65             } catch (SQLException e) {
66                 e.printStackTrace();
67             }
68     }
69     
70 }
复制代码

28行:既然是工具类,一般不要实例化,此时可以采用单例设计模式,或者将构造方法私有化。

26行:很明显可以看到,我们是将连接数据库的URL、用户名,密码等信息编写在一个属性文件(jdbc.properties)中,稍后再来定义这个属性文件。

31行:为避免重复代码,使用静态代码块:只会在类加载的时候执行一次。

42行:定义一个获取数据库连接的方法

60行:关闭数据库连接

(2)接下来新建一个属性文件,new-->file,命名为:db-config.properties,代码如下:

jdbc.url=jdbc:mysql://localhost:3306/jdbcdb
jdbc.username=root
jdbc.password=smyh
jdbc.driver=com.mysql.jdbc.Driver

以后如果需要修改配置信息,只需要在这里改就行了。注意在上面的DBUtils类中是怎么来调用这个配置信息的。

(3)紧接着新建文件,定义好Person类:

复制代码
 1 package com.vae.jdbc;
 2 
 3 public class Person {
 4     private int id;
 5     private String name;
 6     private int age;
 7     private String description;
 8     public int getId() {
 9         return id;
10     }
11     public void setId(int id) {
12         this.id = id;
13     }
14     public String getName() {
15         return name;
16     }
17     public void setName(String name) {
18         this.name = name;
19     }
20     public int getAge() {
21         return age;
22     }
23     public void setAge(int age) {
24         this.age = age;
25     }
26     public String getDescription() {
27         return description;
28     }
29     public void setDescription(String description) {
30         this.description = description;
31     }
32     public Person(int id, String name, int age, String description) {
33         super();
34         this.id = id;
35         this.name = name;
36         this.age = age;
37         this.description = description;
38     }
39     public Person(String name, int age, String description) {
40         super();
41         this.name = name;
42         this.age = age;
43         this.description = description;
44     }
45     public Person() {
46         super();
47         // TODO Auto-generated constructor stub
48     }
49     @Override
50     public String toString() {
51         return "Person [id=" + id + ", name=" + name + ", age=" + age
52                 + ", description=" + description + "]";
53     }
54     
55     
56 }
复制代码

(4)然后开始编写主程序来测试一下:

复制代码
 1 package com.vae.jdbc;
 2 
 3 import java.sql.Connection;
 4 import java.sql.PreparedStatement;
 5 import java.sql.ResultSet;
 6 import java.sql.SQLException;
 7 
 8 
 9 public class Test {
10     
11     public static void main(String[] args) {
12         Person p = new Person();
13         p = findById(1);
14         System.out.println(p);
15     }
16     
17     
18 
19 
20     /**
21      * 查询的方法
22      */
23     public static Person findById(int id){
24         Person p =null;
25         //通过工具类获取数据库连接
26         Connection conn = DBUtils.getConnection();
27         PreparedStatement ps = null;
28         ResultSet rs = null;
29         String sql = "select name,age,description from person where id=?";
30         try {
31             ps = conn.prepareStatement(sql);
32             //设置占位符对应的值
33             ps.setInt(1, id);
34             rs = ps.executeQuery();
35             if(rs.next()){
36                 p = new Person();
37                 p.setName(rs.getString(1));
38                 p.setAge(rs.getInt(2));
39                 p.setDescription(rs.getString(3));
40             }
41         } catch (SQLException e) {
42             e.printStackTrace();
43         }finally{
44             //通过工具类关闭数据库连接
45             DBUtils.close(rs, ps, conn);
46         }
47         return p;
48         
49     }
50 
51 }
复制代码

测试程序是可以运行的。这样,我们的工具类就建好了。

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
2月前
|
存储 SQL 关系型数据库
Mysql学习笔记(二):数据库命令行代码总结
这篇文章是关于MySQL数据库命令行操作的总结,包括登录、退出、查看时间与版本、数据库和数据表的基本操作(如创建、删除、查看)、数据的增删改查等。它还涉及了如何通过SQL语句进行条件查询、模糊查询、范围查询和限制查询,以及如何进行表结构的修改。这些内容对于初学者来说非常实用,是学习MySQL数据库管理的基础。
141 6
|
2月前
|
SQL 关系型数据库 MySQL
Mysql学习笔记(三):fetchone(), fetchmany(), fetchall()详细总结
MySQL中用于数据检索的`fetchone()`, `fetchmany()`, `fetchall()`函数的功能、SQL语句示例和应用场景。
85 3
Mysql学习笔记(三):fetchone(), fetchmany(), fetchall()详细总结
|
2月前
|
SQL Ubuntu 关系型数据库
Mysql学习笔记(一):数据库详细介绍以及Navicat简单使用
本文为MySQL学习笔记,介绍了数据库的基本概念,包括行、列、主键等,并解释了C/S和B/S架构以及SQL语言的分类。接着,指导如何在Windows和Ubuntu系统上安装MySQL,并提供了启动、停止和重启服务的命令。文章还涵盖了Navicat的使用,包括安装、登录和新建表格等步骤。最后,介绍了MySQL中的数据类型和字段约束,如主键、外键、非空和唯一等。
79 3
Mysql学习笔记(一):数据库详细介绍以及Navicat简单使用
|
2月前
|
Java 关系型数据库 MySQL
mysql5.7 jdbc驱动
遵循上述步骤,即可在Java项目中高效地集成MySQL 5.7 JDBC驱动,实现数据库的访问与管理。
485 1
|
2月前
|
关系型数据库 MySQL 数据库
Mysql学习笔记(四):Python与Mysql交互--实现增删改查
如何使用Python与MySQL数据库进行交互,实现增删改查等基本操作的教程。
73 1
|
2月前
|
SQL 分布式计算 关系型数据库
Hadoop-24 Sqoop迁移 MySQL到Hive 与 Hive到MySQL SQL生成数据 HDFS集群 Sqoop import jdbc ETL MapReduce
Hadoop-24 Sqoop迁移 MySQL到Hive 与 Hive到MySQL SQL生成数据 HDFS集群 Sqoop import jdbc ETL MapReduce
110 0
|
2月前
|
SQL 分布式计算 关系型数据库
Hadoop-23 Sqoop 数据MySQL到HDFS(部分) SQL生成数据 HDFS集群 Sqoop import jdbc ETL MapReduce
Hadoop-23 Sqoop 数据MySQL到HDFS(部分) SQL生成数据 HDFS集群 Sqoop import jdbc ETL MapReduce
51 0
|
2月前
|
SQL 分布式计算 关系型数据库
Hadoop-22 Sqoop 数据MySQL到HDFS(全量) SQL生成数据 HDFS集群 Sqoop import jdbc ETL MapReduce
Hadoop-22 Sqoop 数据MySQL到HDFS(全量) SQL生成数据 HDFS集群 Sqoop import jdbc ETL MapReduce
60 0
|
3天前
|
存储 Oracle 关系型数据库
数据库传奇:MySQL创世之父的两千金My、Maria
《数据库传奇:MySQL创世之父的两千金My、Maria》介绍了MySQL的发展历程及其分支MariaDB。MySQL由Michael Widenius等人于1994年创建,现归Oracle所有,广泛应用于阿里巴巴、腾讯等企业。2009年,Widenius因担心Oracle收购影响MySQL的开源性,创建了MariaDB,提供额外功能和改进。维基百科、Google等已逐步替换为MariaDB,以确保更好的性能和社区支持。掌握MariaDB作为备用方案,对未来发展至关重要。
13 3
|
3天前
|
安全 关系型数据库 MySQL
MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!
《MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!》介绍了MySQL中的三种关键日志:二进制日志(Binary Log)、重做日志(Redo Log)和撤销日志(Undo Log)。这些日志确保了数据库的ACID特性,即原子性、一致性、隔离性和持久性。Redo Log记录数据页的物理修改,保证事务持久性;Undo Log记录事务的逆操作,支持回滚和多版本并发控制(MVCC)。文章还详细对比了InnoDB和MyISAM存储引擎在事务支持、锁定机制、并发性等方面的差异,强调了InnoDB在高并发和事务处理中的优势。通过这些机制,MySQL能够在事务执行、崩溃和恢复过程中保持
20 3