我是靠谱客的博主 笨笨龙猫,最近开发中收集的这篇文章主要介绍java操作数据库的事务支持,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一、需求背景:

我们生活经常遇到一个情况:在购买商品的时候,已经支付的了,那么商品应该处于已购买订单里。而不是付款之后,已购买商品没有。

还有转账的时候,转出方和转入方都需要扣减相应的金额,而不是一方减少或者增加。

因为上面的例子都是对数据操作,所以需要我们操作数据库的事务。

如何确定一个事务范围?

事务是由一系列数据库操作组成,他和业务场景有关。当操作完成的时候,如果操作过程没有出现失败,则这个事务产生的数据库操作一并提交(commit)。反之,如果出现失败,则一并回滚(rollback)。

所有事务和业务层(service)确定。

事务的特点:

ACID

   1、原子性:事务里面的操作单元不可切割,要么全部成功,要么全部失败
        2、一致性:事务执行前后,业务状态和其他业务状态保持一致.
        3、隔离性:一个事务执行的时候最好不要受到其他事务的影响
        4、持久性:一旦事务提交或者回滚.这个状态都要持久化到数据库中

 不考虑隔离性会出现的读问题:
        脏读:在一个事务中读取到另一个事务没有提交的数据
        不可重复读:在一个事务中,两次查询的结果不一致(针对的update操作)
        虚读(幻读):在一个事务中,两次查询的结果不一致(针对的insert操作)
    通过设置数据库的隔离级别来避免上面的问题(理解)
        read uncommitted      读未提交    上面的三个问题都会出现
        read committed      读已提交    可以避免脏读的发生
        repeatable read        可重复读    可以避免脏读和不可重复读的发生
        serializable        串行化        可以避免所有的问题

两种方式:

1)数据库上控制事务:

默认情况下,mysql数据库中的事务是自动提交。

1 mysql> show variables like "%autocommit%";
2 +---------------+-------+
3 | Variable_name | Value |
4 +---------------+-------+
5 | autocommit
| ON
|
6 +---------------+-------+
7 1 row in set (0.00 sec

 

我们可以在数据库上进行事务的开启和关闭。但是这种方式显然不好。

2)java代码实现。

查看connection的方法:

1:void commit() 提交事务。Makes all changes made since the previous commit/rollback permanent and releases any database locks currently held by this Connection object.

2:void  rollback()回滚事务.Undoes all changes made in the current transaction and releases any database locks currently held by this Connection object

3:void setAutocommit(boolean ) false 表示开启事务,true表示事务关闭。Sets this connection's auto-commit mode to the given state.

注意:事务要作用同一个数据库连接。

java代码实现有两种方式:

  1、自上到下传递参数:

    通过service传递到dao层的connection的变量,保证整个过程使用的是同一个数据连接。

  2、当前线程绑定事务:

    通过绑定当前线程一个变量(connection),在dao中获取这个connection,保证整个事务的过程中,使用的是同一个连接。

  其中threadLocal方法:ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID)

    该字段在类中要以private  static 来进行修饰。

    1) T  get() 返回当前线程绑定的值。

    2)void  remove() 从当前线程解绑。

    3)void  set(T  value)  绑定当前线程。

内部实现原理就是map方法对currentThread  进行put 和set  remove。

jdbc工具类:

 1 package jd.com.tool_jdbc;
 2
 3 import org.apache.commons.dbcp2.BasicDataSource;
 4 import org.apache.commons.dbcp2.BasicDataSourceFactory;
 5
 6
 7 import java.io.InputStream;
 8 import java.sql.Connection;
 9 import java.sql.PreparedStatement;
10 import java.sql.SQLException;
11 import java.util.Properties;
12
13
14
15 public
class ds_tool {
16
private
static BasicDataSource ds=null;
17
private static Connection con=null;
18
private static ThreadLocal<Connection> threadLocal=new ThreadLocal<>();
19
public
static
BasicDataSource getDs(){
20
try {
21
InputStream inp= ds_tool.class.getClassLoader().getResourceAsStream("database.properties");
22
Properties
pro=new Properties();
23 
pro.load(inp);
24
ds=new BasicDataSourceFactory().createDataSource(pro);
25
ds.setInitialSize(4);
26
ds.setMaxTotal(8);
27
ds.setMaxIdle(2);
28
return
ds;
29
}catch (Exception ex){
30
throw
new RuntimeException("初始化数据库失败"+ex);
31 
}
32
33 
}
34
//给当前线程绑定变量。
35
public
static
BasicDataSource setDs(){
36
try {
37
if(con==null){
38
ds=getDs();
39
con=ds.getConnection();
40
threadLocal.set(con);
41
}else{
42
threadLocal.set(con);
43 
}
44
return
ds;
45
}catch (Exception ex){
46 
ex.printStackTrace();
47
throw
new RuntimeException("初始化错误"+ex);
48 
}
49
50 
}
51
//开启事务
52
public static void
openEven(){
53
try {
54 
setDs();
55
con=threadLocal.get();
56
con.setAutoCommit(false);
57
}catch (Exception ex){
58 
ex.printStackTrace();
59 
}
60
61 
}
62
//提交事务
63
public static void
commEven(){
64
try {
65
con=threadLocal.get();
66 
con.commit();
67
}catch (Exception ex){
68 
ex.printStackTrace();
69 
}
70
71 
}
72
//回滚事务
73
public static
void
rollbackEvent(){
74
try {
75
con=threadLocal.get();
76
System.out.println(con);
77 
con.rollback();
78
}catch (Exception ex){
79 
ex.printStackTrace();
80 
}
81
82 
}
83
public
static
void closedDs(BasicDataSource ds, PreparedStatement pre){
84
try {
85 
ds.close();
86 
pre.close();
87 
threadLocal.remove();
88
}catch (Exception ex){
89 
ex.printStackTrace();
90 
}
91
92 
}
93
94 }

 

然后在业务层上进行事务的控制。

3)1、queryRunner()初始化的时候,不带参数,是默认是开启事务。

  在执行的时候,update(connection con  sql  object ...parm)传入connection。需要关闭资源 connection。

  2、如果quryRunner(Datasource ds)的时候,内部代码会帮我们实现资源回收。不需要connection.close()

转载于:https://www.cnblogs.com/evilliu/p/8665010.html

最后

以上就是笨笨龙猫为你收集整理的java操作数据库的事务支持的全部内容,希望文章能够帮你解决java操作数据库的事务支持所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(69)

评论列表共有 0 条评论

立即
投稿
返回
顶部