TangYuan之事务
1. 事务的定义
Tangyuan中,我们可以通过以下配置定义一个事务:
<transaction id="tx_01" behavior="required" isolation="default" />
transaction节点属性说明:
属性名 | 用途及说明 | 必填 | 取值 |
---|---|---|---|
id | 事务定义标识,不可重复 | Y | 用户定义 |
behavior | 事务的传播级别,默认required,可参考Spring事务,默认required | N | required<br />supports<br />mandatory<br />requires_new<br />not_supported<br />never<br /> |
never | 事务的隔离级别,默认default | N | default<br />read_uncommitted<br />read_committed<br />repeatable_read<br />serializable<br /> |
behavior事务传播属性说明:
取值 | 用途说明 |
---|---|
required | 表示当前方法必须在一个具有事务的上下文中运行,如有客户端有事务在进行,那么被调用端将在该事务中运行,否则的话重新开启一个事务。 |
supports | 表示当前方法不必需要具有一个事务上下文,但是如果有一个事务的话,它也可以在这个事务中运行 |
mandatory | 表示当前方法必须在一个事务中运行,如果没有事务,将抛出异常 |
requires_new | 表示当前方法必须运行在它自己的事务中。一个新的事务将启动,而且如果有一个现有的事务在运行的话,则这个方法将在运行期被挂起,直到新的事务提交或者回滚才恢复执行。 |
not_supported | 表示该方法不应该在一个事务中运行。如果有一个事务正在运行,他将在运行期被挂起,直到这个事务提交或者回滚才恢复执行 |
never | 表示当方法务不应该在一个事务中运行,如果存在一个事务,则抛出异常 |
isolation说明:
取值 | 用途说明 |
---|---|
default | 默认设置,同read_uncommitted |
read_uncommitted | 脏读<br /> * 脏读又称无效数据的读出,是指在数据库访问中,事务T1将某一值修改,然后事务T2读取该值,此后T1因为某种原因撤销对该值的修改,这就导致了T2所读取到的数据是无效的。<br /> * 脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。 因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。 |
read_committed | 不可重复读<br /> * 不可重复读,是指在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。<br /> * 这是由于查询时系统中其他事务修改的提交而引起的。比如事务T1读取某一数据,事务T2读取并修改了该数据,T1为了对读取值进行检验而再次读取该数据,便得到了不同的结果。<br /> * 一种更易理解的说法是:在一个事务内,多次读同一个数据。在这个事务还没有结束时,另一个事务也访问该同一数据。<br /> * 那么,在第一个事务的两次读数据之间。由于第二个事务的修改,那么第一个事务读到的数据可能不一样,这样就发生了在一个事务内两次读到的数据是不一样的,因此称为不可重复读,即原始读取不可重复。 |
repeatable_read | 可重复读取<br />* 可重复读(Repeatable Read),当使用可重复读隔离级别时,在事务执行期间会锁定该事务以任何方式引用的所有行。 因此,如果在同一个事务中发出同一个SELECT语句两次或更多次,那么产生的结果数据集总是相同的。<br /> * 因此,使用可重复读隔离级别的事务可以多次检索同一行集,并对它们执行任意操作,直到提交或回滚操作终止该事务。 |
serializable | 同步事务<br /> * 提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。<br /> * 如果仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。 |
2. 事务的使用
有了上述事务的定义,接下来开始事务的使用。Tangyuan中每个SQL服务都需要使用事务,或者说每个SQL服务在执行期间都需要按照指定的事务定义开启事务,执行SQL命令。我们可以通过三种方式设置SQL服务使用的事务定义。
1.在SQL服务中,手工设置
<selectOne id="getUserById" txRef="tx_01" dsKey="ds">
SELECT * from user WHERE user_id = #{user_id}
</selectOne>
示例中的配置通过txRef
属性手工指定使用tx_01
的事务定义
2.按照SQL服务ID匹配
<setDefaultTransaction type="method">
<property name="select*" value="tx_01"/>
<property name="get*" value="tx_01"/>
<property name="update*" value="tx_02"/>
<property name="insert*" value="tx_02"/>
<property name="delete*" value="tx_02"/>
</setDefaultTransaction>
示例中的配置表示按照SQL服务的名称也就是ID来匹配需要使用的事务定义。比如SQL服务selectUser
将使用tx_01
事务定义,SQL服务updateUser
将使用tx_02
事务定义,需要注意的复合SQL将不会根据setDefaultTransaction
来匹配事务,需要用户手工指定。
3.按照SQL服务类型匹配
<setDefaultTransaction type="command">
<property name="selectOne" value="tx_01"/>
<property name="selectSet" value="tx_01"/>
<property name="update" value="tx_01"/>
<property name="insert" value="tx_01"/>
<property name="delete" value="tx_01"/>
</setDefaultTransaction>
示例中的配置表示按照SQL服务的类型也就是标签来匹配需要使用的事务定义。比如用<selectOne>
标签定义SQL服务将使用tx_01
事务定义,用<update>
标签定义的SQL服务将使用tx_02
事务定义,需要注意的复合SQL将不会根据setDefaultTransaction
来匹配事务,需要用户手工指定。
3. setDefaultTransaction节点配置
Schema设计图
setDefaultTransaction节点属性说明
属性名 | 用途及说明 | 必填 | 取值 |
---|---|---|---|
type | 默认事务的匹配模式 | Y | method:按照SQL服务的名称匹配<br />command:按照SQL服务的类型匹配 |
property节点属性说明
属性名 | 用途及说明 | 必填 | 取值 |
---|---|---|---|
name | method模式下:SQL服务名称,支持*表达式<br />command模式下:SQL服务标签名 | Y | 用户定义 |
value | 需要引用的事务定义ID | Y | 用户定义 |