mysql及java事务

1.mysql事务

        事务(Transaction)是数据库系统中一系列操作的一个逻辑单元,所有操作要么全部成功要么全部失败;目的是为了保证在并发情况下能正确的执行crud操作;

1.1 mysql事务命令

-- 查询mysql事务隔离级别(mysql版本 8.0 以前)
SELECT @@tx_isolation;

-- 设置mysql事务隔离级别为读未提交(mysql版本 8.0 以前)
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

-- 设置mysql事务隔离级别为读已提交(mysql版本 8.0 以前)
set session transaction isolation level read committed;

-- 设置mysql事务隔离级别为可重复读(mysql版本 8.0 以前)
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

-- 设置mysql事务隔离级别为串行化(mysql版本 8.0 以前)
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;

-- 开启事务
START TRANSACTION;
-- 提交
COMMIT;
-- 回滚
ROLLBACK;

1.2 事务的四个特性ACID

        Atomicity(原子性):原子操作,对数据的修改,要么全部成功,要么全部失败。

        Consistent(一致性):在事务开始和完成时,数据都必须保持一致状态。银行转账例子,转出100,另一方在事务完成后一定收到100。

        Isolation(隔离性):数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的”独立“环境执行。

        Durable(持久性):事务完成之后,它对于数据的修改是永久性的,即使出现系统故障也能够保持。

1.3 事务的隔离级别

        read-uncommitted < read-committed < REPEATABLE-READ < SERIALIZABLE(后面比前面严格),不同隔离级别解决并发下的不同问题(脏写、脏读、不可重读、幻读),同时也会存在其它问题。

CREATE TABLE `user_info` (
  `user_id` int(11) DEFAULT NULL,
  `user_name` varchar(50) DEFAULT NULL,
  `user_state` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO user_info(user_id,user_name,user_state)VALUE('1','user1',0);

        脏写(更新丢失):查了很多资料都说是事务A和事务B同时更新一条记录,一个事务回滚导致另一个事务的改动丢失;不过试验了很多次,都没出现,InnoDB引擎下第一个事务已经把要操作的行锁住了,后面的事务无法获取锁,也不能对该行进行修改,自然不会出现脏写。

        目前有两种猜测:1、高并发下,由于数据库的bug,导致出现了两个事务对同一行进行操作,因而出现脏写;2、会不会是两个线程对同一行数据进行操作,一个线程通过代码回滚了另一个线程的数据,导致出现脏写;后面继续研究。

        脏读:一个事务读到了另一个事务未提交的修改数据。事务1

-- 设置mysql事务隔离级别为读未提交(mysql版本 8.0 以前)
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

-- 查询mysql事务隔离级别(mysql版本 8.0 以前)
SELECT @@tx_isolation;

-- 开启事务
START TRANSACTION;

UPDATE user_info SET user_name='tx1' WHERE user_id=1;

-- 在回滚前执行事务2
ROLLBACK;

        事务2可以读到事务1回滚前的修改。

-- 设置mysql事务隔离级别为读未提交(mysql版本 8.0 以前)
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

-- 查询mysql事务隔离级别(mysql版本 8.0 以前)
SELECT @@tx_isolation;

-- 开启事务
START TRANSACTION;

SELECT * FROM user_info;

        避免脏读的方法:设置事务隔离级别为read-committed以上。

        不可重读:事务在读取数据后,再次读取以前读过的数据,发现第二次读出的数据已经发生了改变。

        事务1


-- 设置mysql事务隔离级别为读未提交(mysql版本 8.0 以前)
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- 查询mysql事务隔离级别(mysql版本 8.0 以前)
SELECT @@tx_isolation;

-- 开启事务
START TRANSACTION;

-- 第一次读取user_name
SELECT user_name FROM user_info

-- 等另一个事务修改提交后执行,第二次读取到的user_name与第一次不一样
SELECT user_name FROM user_info

ROLLBACK;

        事务2

-- 设置mysql事务隔离级别为读未提交(mysql版本 8.0 以前)
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;

-- 查询mysql事务隔离级别(mysql版本 8.0 以前)
SELECT @@tx_isolation;

-- 开启事务
START TRANSACTION;

UPDATE user_info SET user_name='tx2' WHERE user_id=1;

COMMIT;

        避免不可重复读的方法:设置隔离级别为可重复读以上。

        幻读:事务在前后两次查询同一个范围数据时,后一次看到了前一次没看到的数据行。

        事务1

-- 设置mysql事务隔离级别为可重复读(mysql版本 8.0 以前)
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
 
-- 查询mysql事务隔离级别(mysql版本 8.0 以前)
SELECT @@tx_isolation;
 
-- 开启事务
START TRANSACTION;

SELECT * FROM user_info WHERE user_id < 10;

-- 另一个事务先执行,再次查询,未查询到user_id为3的记录,接着插入id为3的记录,提交后会发现出现2条id为3的记录
SELECT * FROM user_info WHERE user_id < 10; -- 在该事务内对小于10的记录进行操作,未完全隔离,导致另一个事务可以在该范围内插入数据,造成前面未查询到的幻象
INSERT INTO user_info(user_id, user_name, user_state)VALUE(3, 'user3', 0);

COMMIT;

        事务2

-- 设置mysql事务隔离级别为可重复读(mysql版本 8.0 以前)
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
 
-- 查询mysql事务隔离级别(mysql版本 8.0 以前)
SELECT @@tx_isolation;
 
-- 开启事务
START TRANSACTION;

INSERT INTO user_info(user_id, user_name, user_state)VALUE(3, 'user3', 0);
 
-- 在回滚前执行事务2
COMMIT;

        造成幻读的原因:快照读(查询)和当前读(插入及更新)一起使用。快照读的是某个版本的数据,而插入和更新操作的是最新数据,从而导致快照读有时会漏读最新数据,导致没有看到某个数据的幻象,在这个基础上继续执行更新就有可能出错。

        解决方法:提升事务级别为串行化;或使用select * for update。

2.java事务

2.1 jdbc事务

        业务操作为同一个数据库连接对象,使用的是底层数据库事务。

-- 关闭自动提交
con.setAutoCommit(false);

-- 提交
con.commit();

-- 回滚
con.rollbac();

2.2 spring事务

2.2.1 spring声明式事务

        注解(@Transaction)或xml指定,使用方便,缺点为粒度大(方法级别以上)。注意在声明式事务中也可以手动控制回滚的。

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

2.2.2 spring编程式事务

        将事务管理代码嵌入嵌入到业务代码中,来控制事务的提交和回滚。

@Autowired
private PlatformTransactionManager transactionManager;

public void testTransaction() {

  TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
          try {
               // ....  业务代码
              transactionManager.commit(status);
          } catch (Exception e) {
              transactionManager.rollback(status);
          }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
JavaMySQL双写事务是指在使用Java编程语言与MySQL数据库进行交互时,实现同时对多个数据源进行写操作的事务控制。在这种情况下,Java应用程序与MySQL数据库之间通过Java连接数据库和MySQL数据库的事务管理机制进行协调,确保数据的一致性和完整性。 在Java中,可以通过使用JDBC(Java数据库连接)或其他ORM(对象关系映射)框架来实现对MySQL数据库的连接和数据操作。而在MySQL中,可以使用事务控制语句来保证数据库操作的原子性、一致性、隔离性和持久性。 在双写事务中,可能需要对多个数据库进行同时的写操作,这就需要确保在Java应用程序中对多个数据库的写操作能够在一个事务中进行。这时候就需要使用分布式事务管理、跨库事务等技术来实现对多个数据库进行同时写操作的事务控制。 例如,可以使用Java中的分布式事务管理框架(如Atomikos、Bitronix等)来协调多个数据源的写操作,保证它们要么全部成功,要么全部失败。同时,在MySQL中,可以通过使用XA事务或者使用存储过程来实现跨库事务的控制。 总之,JavaMySQL双写事务需要通过Java应用程序和MySQL数据库之间的事务管理机制进行协调,确保对多个数据库进行写操作时的原子性和一致性。需要结合Java的连接数据库技术和MySQL事务控制技术,来完成对多个数据源的同时写操作的事务控制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kenick

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值