mysql事物 - LBCC

mysql事物 - LBCC,第1张

建表如下:

对于实验数据中的age列,现有的数据为1,5,9,11,那么针对age列将会有1,5,9,11这4个锁,当筛选条件中的column被精准命中时,也就是说sql中写成where age = x时,这是被 *** 作的记录,将会被锁定。举个例子:

开启2个事物session1,session2

直接执行行3,箭头指向的位置一直在转圈,无法对age=5的记录加排它锁。

现有的数据为1,5,9,11,那么对于age列,将会有以下几个开区间

(-∞, 1), (1, 5), (5, 9), (9, 11), (11, +∞)。

直接执行行4,能看到一直在转圈。因为age >6 and age <8落在了(9, 11)这个开区间内,那么(9, 11)这个开区间内的与age列相关的dml语句都会被锁。这里演示的是insert,那么update的?没有update,因为既然有(9, 11)这个开区间,那么就说明(9, 11)的间隙里没有数据。

与间隙锁的区别:查询条件落只在间其中一个开区间内,将会进行锁定。临键锁则是,当查询条件跨越了超过一个开区间,比如:where age >6 and age <10,这个条件落在了(5, 9), (9, 11)这2个区间内,它让存在的记录锁里的age=9也被包含在了符合的条件里。这是就会有如下临键锁了

(-∞, 1], (1, 5], (5, 9], (9, 11], (11, +∞),可以看到临键锁就是记录锁与间隙锁的并集,是一个左开右必的区间。这是,将会对被落到的区间内的符合条件的记录进行锁定,(5, 9], (9, 11]被锁定,也就是(5, 11]这个区间内的记录被锁定了。下面来 *** 作:

MySQL的事务如果不在任何修改,默认是自动提交的,也就是你只要执行一个SQL,回车之后这个SQL语句如果没有任何问题,只需完成后是自动提交的。

控制这个功能的参数是:autocommit。如果这个参数的值是on或者1,那么就是上面我说的那种现象。如果是off或者0,则表示不会自动提交事务。需要你显示的去提交事务。否则锁执行的SQL不会不会永久生效,只会对你当前命令行的session有效,退出MySQL后,执行的SQL语句将会别回滚。

当你需要两个SQL语句同时成功或者同时失败的时候,你可以手动地开启一个事务。比如下面的场景:

你想向订单表order_info表中插入一条新的订单记录,同时要想支付信息表payment_info中插入一条支付信息记录,这个时候从业务的角度上来看,这两个表中的插入 *** 作,需要保持原子性(也就是事务的四大特性之一),也就是要么都插入成功,要么都插入失败,不能存在订单插入成功,支付插入失败,反之也不可以。

要满足上面的需求,你就需要手动的去开启一个事务,在这个事务中去插入两个表中的数据。然后再提交这个事务。如果这两个表的插入 *** 作,你不手动的开启事务,MySQL自己会把两个SQL语句分开放在两个单独的事务中。执行一个插入,就会自动提交一个事务,然后在执行另外一个插入,再自动提交另外一个事务。

在MySQL看来,这是两个分别向两个表中插入的SQL语句而已,它不会从业务上考虑这两个SQL实际的业务逻辑背景是什么。所以此时他会看成是两个SQL语句,也就是两个事务。

这样的情况下就需要手动的开启事务。

如何用java开启mysql事务,要求详细

看你是什么事务,jdbc事务,还是分布式事务,还是容器事务

1,编程式事务管理(jdbc的事务是绑定在connection上的)

Connection conn = null

try

{

Class.forName("com.mysql.jdbc.Driver")

conn = DriverManager.getConnection("jdbc:oracle:thin:@host:1521:SID","username","password")

conn.setAutoCommit(false) //取消自动提交

PreparedStatement ps = conn.prepareCall("update something")

ResultSet rs = ps.executeQuery()

conn.commit() //手动提交

}

catch (Exception e)

{

conn.rollback()

e.printStackTrace()

}

finally

{

conn.close()

}

2,声明式事务

先在工程的application.xml配置文件中添加如下代码,开启事务

<!-- 声明式事务控制配置 -->

<tx:annotation-driven transaction-manager="txManager"/>

<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="datasource" ref="bassDataSource"></property>

</bean>

然后在你需要开启事务的接口前面添加注解

@Transactional(rollbackFor = IOException.class)

public void add(String name) throws IOException

{

System.out.println("可以再类里和方法里面添加事务注解0~0")

throw new IOException()

}

直接调用接口方法就好

分布式事务处理(mysql貌似在5.X之后才支持) 的话,

1.可以直接使用spring+atomikos框架进行管理

参考:http://blog.chinaunix.net/uid-21162795-id-3424973.html

就不贴测试代码了,自己看着配置吧

2,使用JTA(Java Transaction API)进行分布式事务管理(测试代码如下)

import java.sql.Connection

import java.sql.PreparedStatement

import java.sql.SQLException

import javax.naming.InitialContext

import javax.sql.DataSource

import javax.transaction.SystemException

import javax.transaction.UserTransaction

import com.mysql.jdbc.jdbc2.optional.MysqlDataSource

//分布式事务处理

public class transferAccount

{

@SuppressWarnings("null")

public void testTransferAccount()

{

UserTransaction userts = null

Connection connA = null

PreparedStatement psA = null

InitialContext context = null

Connection connB = null

PreparedStatement psB = null

try

{

//获得事务管理对象

userts = (UserTransaction) context.lookup("java:comp/UserTransaction")

//获取两个数据库

connA = getDataSourceA().getConnection()

connB = getDataSourceB().getConnection()

//开启事务

userts.begin()

//sql语句

psA = connA.prepareStatement("我加1")

psB = connB.prepareStatement("我减1")

//执行sql

psA.executeUpdate()

psB.executeUpdate()

//事务提交

userts.commit()

} catch (Exception e)

{

try

{

userts.rollback()

} catch (IllegalStateException | SecurityException

| SystemException e1)

{

e1.printStackTrace()

}

e.printStackTrace()

}

finally

{

try

{

psA.close()

psB.close()

connA.close()

connB.close()

} catch (SQLException e)

{

e.printStackTrace()

}

}

}

public DataSource getDataSourceA()

{

MysqlDataSource dataSource = new MysqlDataSource()

dataSource.setDatabaseName("mysql")

dataSource.setServerName("server")

dataSource.setPortNumber(1433)

dataSource.setUser("test")

dataSource.setPassword("test")

return dataSource

}

public DataSource getDataSourceB()

{

MysqlDataSource dataSource = new MysqlDataSource()

dataSource.setDatabaseName("mysql")

dataSource.setServerName("server")

dataSource.setPortNumber(1435)

dataSource.setUser("test1")

dataSource.setPassword("test1")

return dataSource

}

}


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/8564809.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-18
下一篇 2023-04-18

发表评论

登录后才能评论

评论列表(0条)

保存