bboss persistent的事务管理框架实现数据库的增、删、改、查事务管理,整个事务管理框架在下面的各节中详细介绍。事务管理框架的实现原理模型见下图:
应用程序中的事务TX都会和本地线程关联,本地线程ThreadLocal是一个对上下文Thread关联的线程独占资源进行有效管理的容器。
4.9.1 .多数据库事务的支持(分布式事务)
一个事务中如果存在不同数据库的操作,那么事务的处理比较复杂,只有所有的数据库的操作都成功以后事务提交,否则事务回滚。下面的代码演示了如果管理两个不同数据库(分布式)事务:
Poolman.xml中配置了两个数据源bspf和query:
<datasource>
...
<dbname>bspf</dbname>
...
</datasource>
<datasource>
...
<dbname>query</dbname>
...
</datasource>
代码段如下:
TransactionManager tm = new TransactionManager();
try
{
tm.begin();
DBUtil db = new DBUtil();
//在bspf库上执行删除操作
db.executeDelete("bspf","delete from table1 where id=1");
//在query库上执行更新操作
db.executeUpdate("query","update table1 set value='test'
where id=1");
tm.commit();
}
catch(Exception e)
{
try {
tm.rollback();
} catch (RollbackException e1) {
e1.printStackTrace();
}
}
上述代码中对bspf库上执行删除操作,在query库上执行更新操作,两个操作被包含在一个事务中,只有两个操作全部成功后事务才会成功,任何一个失败,都会导致事务被回滚。
4.9.2 .四种类型的事务
a. 必须创建新的事务(NEW_TRANSACTION)
b. 有事务就加入当前事务,没有就不创建事务(MAYBE_TRANSACTION)
c. 有事务就加入当前事务,没有就创建事务(REQUIRED_TRANSACTION)(默认情况)
d. 没有事务(NO_TRANSACTION)
4.9.3 .事务嵌套
对于同一个的事务中包含的事务定义为事务嵌套,事务所包含的子事务通过子事务计数器来管理,增加一个子事务时计数器加1,提交一个子事务时计数器减一,当计数器为零时提交所有事务,只要事务执行过程中有rollback的情况则回滚全部子事务。事务的嵌套具有一下16种组合,每种组合对全局事务的影响见表:
| 内部事务类型 | |||
外部事 务类型 | NEW_TRANSACTION | REQUIRED_TRANSACTION | MAYBE_TRANSACTION | NO_TRANSACTION |
NEW_TRANSACTION | 屏蔽声明的事务,程序中开启一个新事务 | 使用声明的事务 | 使用声明的事务 | 屏蔽声明的事务,程序在没有事务的环境下运行 |
REQUIRED_TRANSACTION | 屏蔽声明的事务,程序中开启一个新事务 | 使用声明的事务 | 使用声明的事务 | 屏蔽声明的事务,程序在没有事务的环境下运行 |
MAYBE_TRANSACTION | 如果声明的事务存在,屏蔽声明的事务,程序中开启一个新事务 | 如果声明的事务存在,则使用声明的事务,否则开启一个新的事务 | 如果声明的事务存在,则使用声明的事务,否则不需声明事务 | 如果声明的事务存在,屏蔽声明的事务,程序在没有事务的环境下运行 |
NO_TRANSACTION | 程序中开启一个新事务 | 程序中开启一个新事务 | 程序在没有事务的环境下运行 | 程序在没有事务的环境下运行 |
4.9.4 .支持事务的挂起和恢复
事务的挂起包括挂起当前正在执行的事务和挂起所有的事务.
挂起当前正在执行的事务是指暂停当前线程中运行的事务。如果在执行当前事务之前有事务挂起则恢复之前挂起的事务,
挂起所有的事务是指将当前事务挂起同时不恢复之前事务,即在执行恢复之前的当前环境没有事务关联。
事务恢复:将之前挂起的事务进行恢复,事务继续执行
4.9.5 事务管理的相关接口
事务管理器:com.frameworkset.orm.transaction.TransactionManager ,每个
接口表:
名称 | 功能描述 | 说明 |
|
|
public void begin() throws TransactionException | 开启一个事务,如果当前上下文有事务则加入,如果没有则创建新的事务 | Begin方法只能在TransactionManager的同一个对象实例上调用一次,超过一次将抛出事务异常 |
|
|
public void begin(int tx_type) throws TransactionException | 开启一个事务,参数tx_type值的取值范围为: NEW_TRANSACTION-开启新事务,隔离上下文事务 REQUIRED_TRANSACTION-有则加入事务,没有就开启新事物 MAYBE_TRANSACTION-有则加入事务,没有就不开启事务 NO_TRANSACTION-不开启事务也不加入上下文事务 |
|
|
|
public void commit() throws RollbackException | 提交事务,如果是嵌套子事务,则事务计数器递减直至为0时提交全部嵌套事务,只有所有子事务都提交成功后才算提交成功 |
|
|
|
public void rollback() throws RollbackException | 回滚事务,如果事务执行过程当中出现异常,则回滚事务 |
|
|
|
public JDBCTransaction suspend() throws SystemException | 挂起事务,挂起当前正在执行的事务是指暂停当前线程中运行的事务。如果在执行当前事务之前有事务挂起则恢复之前挂起的事务 |
|
|
|
public JDBCTransaction suspendAll() throws SystemException | 挂起所有的事务,挂起所有的事是指将当前事务挂起同时不恢复之前事务,即在执行恢复之前的当前环境没有事务关联。
|
|
|
|
public void resume(JDBCTransaction tx) throws InvalidTransactionException,
IllegalStateException, SystemException | 恢复之前挂起的事务 |
|
|
|
4.9.7 应用程序使用事务框架进行编程的两种方式
应用程序使用事务框架进行编程的具有以下两种方式
l 可编程的事务管理模式
可编程的事务管理模式就是说可以直接在业务程序中直接调用事务管理的接口来进行事务处理,在这种模式下同样可以采用两种方式进行编程,一种是程序员直接在代码中创建事务对象,开启事务,提交或者回滚事务;一种是通过系统提供的事务管理模板接口来编写事务控制程序。前者容易造成事务泄漏(没有被正常的提交或者回滚),但是使用起来比较直观,后者将事务管理的功能全部封装在执行模板方法的功能类中,开发人员只需在模板方法中编写包含数据库操作的业务功能即可,不会出现事务泄漏的情况。
l 声明式的事务管理模式
声明式的事务管理模式就是指将业务组件的事务控制策略全部通过配置文件的来声明实现,业务组件本身无需对事物进行管理,具体进行配置的规则简单描述如下:
第一步 将业务组件配置到配置文件中
第二步 需要控制事务的方法名添加到配置文件中
第三步 定义事务控制策略,即在什么情况下事务执行成功,什么情况下事务执行失败,也就说需要定义失败的策略,失败策略一般通过定义一些特定的异常来声明,也可以不定义异常,默认所有的异常都会导致事务回滚。
声明性事务的实现是基于系统中提供的轻量级aop框架来实现的,通过该框架可以对业务组件中所有需要进行事务控制的方法进行实时动态拦截嵌入事务的控制功能,具体的细节请参照《aop框架的使用文档》。
4.9.8 可编程事务使用实例
1.简单的事务处理-【开始】>【提交】>【回滚】
TransactionManager tm = new TransactionManager();
try {
tm.begin();
log("delete befer" ,tm.getStatus());
DBUtil dbUtil = new DBUtil();
dbUtil.executeDelete("delete from test");
dbUtil.executeDelete("delete from test1");
log("delete after" ,tm.getStatus());
tm.commit();
log("delete commit after" ,tm.getStatus());
} catch (TransactionException e) {
try {
tm.rollback();
} catch (RollbackException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
try {
tm.rollback();
} catch (RollbackException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
2.事务挂起处理-【开始】>【挂起】>【恢复】>【提交】>【回滚】
TransactionManager tm = new TransactionManager();
try {
//开始事务,在begin和commit之间的各种数据库操作都包含在事务中,除非中间有事务的挂起和中断,但是中断恢复后事务将继续,
//或者另外在事务执行过程如果开启了新的事务,则当前事务将被中断
tm.begin();
log("delete before",tm.getStatus());
DBUtil dbUtil = new DBUtil();
//执行两个删除操作,如果一个失败整个事务就回滚
dbUtil.executeDelete("delete from test");
dbUtil.executeDelete("delete from test1");
//挂起事务,挂起后的数据库操作将不受事务控制直到事务被恢复
JDBCTransaction tx = tm.suspend();
try
{
dbUtil.executeInsert("insert into test1(name) values('biaoping.yin')");
}
catch(Exception e)
{
}
//恢复事务,之后的事务将加入之前被中断的事务当中
tm.resume(tx);
log("delete after",tm.getStatus());
dbUtil.executeInsert("insert into test1(name) values('biaoping.yin1')");
//提交事务
tm.commit();
log("delete commit",tm.getStatus());
} catch (TransactionException e) {
log("delete rollback before",tm.getStatus());
try {
//回滚事务
tm.rollback();
} catch (RollbackException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
log("delete rollback after",tm.getStatus());
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
log("delete rollback1 before",tm.getStatus());
try {
tm.rollback();
} catch (RollbackException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
log("delete rollback1 after",tm.getStatus());
}
3.指定开启的事务类别
TransactionManager tm = new TransactionManager();
//开始事务,在begin和commit之间的各种数据库操作都包含在事务中,除非中间有事务的挂起和中断,但是中断恢复后事务将继续,
//或者另外在事务执行过程如果开启了新的事务,则当前事务将被中断
tm.begin(TransactionManager.REQUIRED_TRANSACTION);
tm.begin(TransactionManager.NEW_TRANSACTION);
tm.begin(TransactionManager. MAYBE_TRANSACTION);
tm.begin(TransactionManager. NO_TRANSACTION);
4.使用事务处理模板类对事务处理进行封装
相关的接口如下:
com.frameworkset.common.poolman.JDBCTemplate 不带返回值模板接口
com.frameworkset.common.poolman.JDBCValueTemplate 带返回值的模板接
com.frameworkset.common.poolman.TemplateDBUtil 提供执行上述两种模板接口的两个静态工具方法,对底层的事务进行了有效的封装。
l 不带返回值的模板方法使用实例
TemplateDBUtil.executeTemplate(
new JDBCTemplate(){
/**
* 整个execute()方法的执行都会被包含在一个数据库事务中
* 当有异常抛出时TemplateDBUtil.executeTemplate()方法就
* 会自动回滚整个数据库事务,
* 当整个方法正常结束后,事务就会自动被提交。
* 通过模板工具提供的便利,开发人员不需要编写自己的事务代码就
* 可以顺利地实现数据库的事务性操作
*/
public void execute() throws Exception {
DBUtil dbUtil = new DBUtil(); PreparedDBUtil db = null;
try {
for (int i = 0; i < 10; i++) {
db = new PreparedDBUtil();
db.preparedInsert(
"insert into td_reg_bank_acc_bak (create_acc_time,starttime,endtime) values(?,?,?)");
Date today = new Date(new java.util.Date().getTime());
db.setDate(1, new java.util.Date());
db.setDate(2, new java.util.Date());
db.setDate(3, new java.util.Date());
db.executePrepared();
}
}
catch(Exception e)
{
throw e;//抛出异常,将导致整个数据库事务回滚
}
try
{
dbUtil.executeInsert("insert into td_reg_bank_acc_bak (clob1,clob2) values('aa','bb')");
}
catch(Exception e)
{
throw e;//抛出异常,将导致整个数据库事务回滚
}
//方法顺利执行完成,事务自动提交
}
}
);
l 带返回值的模板方法使用实例
Object ret = TemplateDBUtil.executeTemplate(
new JDBCValueTemplate(){
/**
* 整个execute()方法的执行都会被包含在一个数据库事务中
* 当有异常抛出时TemplateDBUtil.executeTemplate()方法就会自动回滚整个数据库事务
* 当整个方法正常结束后,事务就会自动被提交,并将返回值返回给调用程序。
* 通过模板工具提供的便利,开发人员不需要编写自己的事务代码就可以顺利地实现数据库的事务性操作
*/
public Object execute() throws Exception {
DBUtil dbUtil = new DBUtil(); PreparedDBUtil db = null;
try {
for (int i = 0; i < 1; i++) {
db = new PreparedDBUtil();
db.preparedInsert("insert into " +
"td_reg_bank_acc_bak " + "(create_acc_time,starttime,endtime) " +
"values(?,?,?)");
Date today = new Date(
new java.util.Date().getTime());
db.setDate(1, new java.util.Date());
db.setDate(2, new java.util.Date());
db.setDate(3, new java.util.Date());
db.executePrepared();
}
}
catch(Exception e)
{
throw e;//抛出异常,将导致整个数据库事务回滚
}
try
{
dbUtil.executeInsert("insert into " +
"td_reg_bank_acc_bak " +
"(clob1,clob2) values('aa','bb')");
}
catch(Exception e)
{
throw e;//抛出异常,将导致整个数据库事务回滚
}
//方法顺利执行完成,事务自动提交,并返回方法的返回值
return "go";
}
}
);
4.9.9 声明式事务使用实例
4.9.9 .1声明式事务简介
声明式事务通过系统中基于java动态代理机制的aop框架实现,这个框架对业务组件进行有效的管理,包括业务组件的依赖注入,业务组件同步方法调用管理,业务组件拦截器的配置管理,业务组件方法事务控制。要想实现这些功能只需将业务组件配置到xml文件中即可,配置文件主文件在位于classes目录下,主文件为manager-provider.xml,可以有多个配置文件,将这些文件相对路径配置到主文件中,再通过BaseSPIManager组件提供的管理接口获取每个业务组件的接口实例即可。
4.9.9 .2声明式事务配置管理
l 配置语法
整个aop框架的xml配置文件语法如下:
<!--
manager-config(manager+,mangerimport*)
manager(provider+,synchronize?,transactions?,reference*,interceptor*)
manager-attributelist{
id-管理服务者id
jndiname-管理服务者jndi属性,目前未使用
singlable-是否是单实例模式
default-是否是缺省管理服务
interceptor-管理服务器的拦截器
}
##
# 如果在系统中配置了多个拦截器,整个框架能够确保每个拦截器都被调用
# 调用的顺序为 拦截器配置的顺序,如果同时通过manager节点的属性interceptor定义了一个拦截器,
# 则会首先调用这个属性对应的拦截器,然后再调用其他拦截器
##
interceptor(pcdata)
interceptor-attributelist{
class-拦截器的实现类,所有的拦截器都必须实现
com.frameworkset.proxy.Interceptor接口
目前系统中提供了以下缺省拦截器:
数据库事务管理拦截器(com.chinacreator.spi.
interceptor.TransactionInterceptor),支持对声明式事务的管理
}
reference(pcdata)
reference-attributelist{
fieldname-对应的管理服务提供者中的字段名称,必选属性
refid-引用的管理服务的id,对应manager节点的id属性,必选属性
reftype-对应的管理服务提供者类型,可选属性
}
provider(pcdata)
provider-attributelist{
type-服务提供者标识id
used-服务提供者是否被启用,缺省值为false
class-服务提供者对应的class类
prior-provider调用的优先级
}
synchronize(method+)
synchronize-attributelist{
enabled-是否启用同步功能,如果没有启用同步功能
即使配置了多个服务提供者的同步方法,所有的同步功能将不起作用
}
transactions(method+)
method(param*,rollbackexceptions?)
method-attributelist{
name-方法名称,name和pattern不能同时出现
pattern-匹配方法名称的正则表达式
txtype-需要控制的事务类型,取值范围:
NEW_TRANSACTION,
REQUIRED_TRANSACTION,
MAYBE_TRANSACTION,
NO_TRANSACTION
}
param(pcdata)
param-attributelist{
type-
}
rollbackexceptions(exception+)
exception(pcdata)
exception-attributelist{
class-
type-IMPLEMENTS,INSTANCEOF
}
mangerimport(pcdata)
mangerimport-attributelist{
file-
}
-->
在上述配置语法中的粉红色规则就是与声明式事务相关的语法。这里只介绍有关事务的配置语法。
l 配置步骤
从上述的语法当中可以看出,要声明一个业务组件的事务方法的步骤为:
第一步 准备好业务组件,参考下面的模型
第二步 在配置文件中配置一个管理服务,也就是添加一个manager元素(指定管理服务的惟一标识id属性,是否单实例singlable属性),
第三步 在manager中配置一个或者多个provider(管理服务提供者,每个管理服务提供者需要指定自己的type属性,以及具体的实现类class)
第四步 在transactions元素中使用method元素、rollbackexcepiton元素、exception元素、param元素声明所有需要进行事务控制的方法以及控制事务的规则。
l 配置示例
<manager-config>
<manager id="tx.a" singlable="false" >
<!--
属性描述:
type:代表数据存储的类型,例如DB,LDAP,ACTIVEDIRECTORY等等
default:缺省实现,不管used是否指定都会在同步方法中调用
class:实现类代码
used:标识是否使用,默认为false
-->
<provider type="DB" default="true"
class="com.chinacreator.spi.transaction.A1" />
<!--
在下面的节点对provider的业务方法事务进行定义
只要将需要进行事务控制的方法配置在transactions中即可
-->
<transactions>
<!--
定义需要进行事务控制的方法
属性说明:
name-方法名称,可以是一个正则表达式,正则表达式的语法请参考jakarta-oro的相关文档,如果使用
正则表达式的情况时,则方法中声明的方法参数将被忽略,但是回滚异常有效。
pattern-方法名称的正则表达式匹配模式,通常匹配
txtype-需要控制的事务类型,取值范围:
NEW_TRANSACTION,
REQUIRED_TRANSACTION,
MAYBE_TRANSACTION,
NO_TRANSACTION
-->
<!--
模式匹配,模式匹配的顺序受配置位置的影响,如果配置在后面或者中间,那么会先执行之前的方法匹配,如果匹配上了就不会
对该模式方法进行匹配了,否则执行匹配操作。
如果匹配上特定的方法名称,那么这个方法就是需要进行同步的方法
模式testInt.*匹配接口中以testInt开头的任何方法
-->
<method name="testTXInvoke" txtype="NEW_TRANSACTION">
<param type="java.lang.String"/>
</method>
<method name="testTXInvoke" txtype="REQUIRED_TRANSACTION"/>
<method name="testTXInvokeWithReturn" txtype="REQUIRED_TRANSACTION"/>
<method name="testTXInvokeWithException" txtype="MAYBE_TRANSACTION"/>
<method name="testSameName" txtype="NO_TRANSACTION"/>
<method name="testSameName1">
<param type="java.lang.String"/>
</method>
<!--
定义使事务回滚的异常,如果没有明确声明需要回滚事务的异常,那么当有异常发生时,事务管理框架将自动回滚当前事务
class-异常的完整类路径
type-是否检测类型异常的子类控制标识,
IMPLEMENTS只检测异常类本身,忽略异常类的子类;
INSTANCEOF检查异常类本省及其所有子类
-->
<method name="testTXWithSpecialExceptions">
<rollbackexceptions>
<exception class="com.chinacreator.spi.transaction.RollbackInstanceofException"
type="INSTANCEOF"/>
<exception class="com.chinacreator.spi.transaction.Exception1"
type="IMPLEMENTS"/>
</rollbackexceptions>
<param type="java.lang.String"/>
</method>
<method name="testTXWithInstanceofExceptions">
<rollbackexceptions>
<exception class="com.chinacreator.spi.transaction.RollbackInstanceofException"
type="INSTANCEOF"/>
</rollbackexceptions>
<param type="java.lang.String"/>
</method>
<method name="testTXWithImplementsofExceptions">
<rollbackexceptions>
<exception class="com.chinacreator.spi.transaction.RollbackInstanceofException"
type="IMPLEMENTS"/>
</rollbackexceptions>
<param type="java.lang.String"/>
</method>
<!--
如果涉及的方法名称是一个正则表达式的匹配模式,则无需配置方法参数
如果指定的方法没有参数则无需指定参数
注意参数出现的位置顺序和实际方法定义的参数顺序保持一致
模式为* 表示匹配所有的方法
-->
<!--
通过模式方法进行声明式事务控制,同时声明了需要回滚事务的异常
pattern【testPatternTX[1-9.]*】表示以testPatternTX开头的所有方法
-->
<!--<method pattern="testPatternTX[1-9.]*">
<rollbackexceptions>
<exception class="com.chinacreator.spi.transaction.RollbackInstanceofException"
type="IMPLEMENTS"/>
</rollbackexceptions>
<param type="java.lang.String"/>
</method>-->
<!-- 通过模式方法进行声明式事务控制
pattern【testPatternTX[1-9.]*】表示以testPatternTX开头的所有方法
-->
<method pattern="testPatternTX[1-9.]*">
<param type="java.lang.String"/>
</method>
<!--
系统级别的异常java.lang.NullPointException,导致事务回滚
-->
<method name="testSystemException">
<rollbackexceptions>
<exception class="com.chinacreator.spi.transaction.RollbackInstanceofException"
type="IMPLEMENTS"/>
</rollbackexceptions>
</method>
<!--
系统级别的异常java.lang.NullPointException,导致事务回滚
-->
</transactions>
</manager>
</manager-config>
l 事务控制规则
根据实际情况事务控制规则划分为:
1. 不带参数方法
<method name="testTXInvoke"/>
说明:指定需要控制事务的方法为testTXInvoke,这里没有声明事务类型,默认的事务类型为REQUIRED_TRANSACTION
在这种规则下一旦方法执行时向外抛出异常,则会导致事务回滚,如果方法正常结束则事务提交。如果声明了回滚异常规则,则按照回滚异常规则控制事务的回滚和提交。
2. 带参数事务方法,只声明需要进行事务控制的方法信息,包括方法的名称和方法参数
<method name="testTXInvoke">
<param type="java.lang.String"/>
</method>
说明:指定需要控制事务的方法为testTXInvoke,并且方法的带一个String类型的参数,这里没有声明事务类型,默认的事务类型为REQUIRED_TRANSACTION
在这种规则下一旦方法执行时向外抛出异常,则会导致事务回滚,如果方法正常结束则事务提交。如果声明了回滚异常规则,则按照回滚异常规则控制事务的回滚和提交。
如果参数为数组时,需要配置param的type属性需要指定为特定类型的数组类型名称,比如字符串数组类型为:[Ljava.lang.String;
3. 指定事务类型规则
<method name="testTXInvoke" txtype="REQUIRED_TRANSACTION">
<param type="java.lang.String"/>
</method>
说明:指定需要控制事务的方法为testTXInvoke,并且方法的带一个String类型的参数,同时通过txtype属性明确地将事务类型指定为
REQUIRED_TRANSACTION
Txtype属性的取值范围如下,具体的含义参考【 4.9.2 】节:
NEW_TRANSACTION,
REQUIRED_TRANSACTION,
MAYBE_TRANSACTION,
NO_TRANSACTION
在这种规则下一旦方法执行时向外抛出异常,则会导致事务回滚,如果方法正常结束则事务提交。如果声明了回滚异常规则,则按照回滚异常规则控制事务的回滚和提交。
4. 通过模式指定控制事务的方法范围
<method pattern="testPatternTX[1-9.]*"
txtype="REQUIRED_TRANSACTION">
<param type="java.lang.String"/>
</method>
说明:通过pattern属性指定了一个模式testPatternTX[1-9.]*,表示以testPatternTX开头的所有方法都需要控制事务
Name属性和pattern属性只能设定一个,如果同时设定了两个属性,则只有pattern生效,name无效。
在这种规则下一旦方法执行时向外抛出异常,则会导致事务回滚,如果方法正常结束则事务提交。如果声明了回滚异常规则,则按照回滚异常规则控制事务的回滚和提交。
5. 指定事务的回滚异常
<method name="testSystemException">
<rollbackexceptions>
<exception class="com.chinacreator.spi.transaction.RollbackInstanceofException"
type="IMPLEMENTS"/>
</rollbackexceptions>
</method>
或者
<method name="testSystemException">
<rollbackexceptions>
<exception class="com.chinacreator.spi.transaction.RollbackInstanceofException"
type="INSTANCEOF"/>
</rollbackexceptions>
</method>
说明:声明事务方法时,可以通过rollbackexceptions和exception元素指定方
法事务回滚的异常信息,包括异常名称,异常的范围类型:IMPLEMENTS,INSTANCEOF。异常名称通过class属性执行,范围类型通过type属性指定,只能设置IMPLEMENTS和INSTANCEOF这两个值。IMPLEMENTS类型指异常只能是异常本身的对象,其子类不属于回滚异常,INSTANCEOF类型指异常本身和其子类都属于回滚异常。
除了指定的回滚异常需要回滚事务外,如果抛出的异常是系统级别的异常,即使这些异常没有进行声明,也会导致事务回滚。系统级别的异常是指以下几种异常:
java.lang.RuntimeException及其子类
java.lang.Error及其子类
另外以下几种异常也是默认回滚事务的异常:
java.sql.SQLException
javax.transaction.RollbackException
com.frameworkset.orm.transaction.TransactionException
4.9.9 .3 BaseSPIManager组件
l 包路径及接口说明
BaseSPIManager的完整包路径如下:
com.chinacreator.spi.BaseSPIManager
BaseSPIManager提供了以下两个静态管理接口:
l 接口1 获取id为managerid的管理服务接口实例
AI a = (AI)BaseSPIManager.getProvider("managerid");
l 接口2 获取id为managerid的管理服务接口实例,参数二对应多个provider中相应的provider 类型标识
AI a = (AI)BaseSPIManager.getProvider("managerid","providertype");
方法1和方法2的区别是:方法1的返回值和抛出的异常以默认的provider的相应方法的返回值和异常为准,方法2返回值和抛出的异常以指定类型的provider的相应方法的返回值和异常为准。方法1和方法2的事务管理机制是一致和相同的。
这两个接口返回的对象类型为java.lang.Object,调用程序可以将该对象转型为相应的组件接口类型。
l 使用BaseSPIManager获取组件实例和直接创建组件实例的区别
只有通过BaseSPIManager提供的两个方法获取接口实例,然后在接口实例上调用事务方法,声明的事务管理才会生效,否则无效。举例说明如下:
假如接口AI和接口实现类A,接口中定义了方法handle,并且将该方法声明为事务方法,
在配置文件中做以下的配置:
<manager id="test.A" singlable="true" >
<provider type="DB" default="true"
class="test.A" />
<transactions>
<method name="handle" txtype="REQUIRED_TRANSACTION"/>
</transactions>
</manager>
声明组件的管理id为test.A,我们通过以下两种方式获取接口实例:
方法1 直接创建对象实例a,在实例a上调用handle方法
AI a = new A();
a.handle();
采用这种方式时,为handle方法声明的事务不会生效。
方法2 通过BaseSPIManager提供的接口获取接口实例
AI a = (AI)BaseSPIManager.getProvider("test.A");
a.handle();
采用这种方式,为handle方法声明的事务才会生效。
业务组件必须由两部分组成:组件接口,组件接口的实现类;这是因为通过BaseSPIManager的两个方法所获取到的对象必需是一个接口对象,这里不能直接将返回值直接转换为具体的实现类型,以下的用法是正确的:
AI a = (AI)BaseSPIManager.getProvider("test.A");
以下的用法是不正确的,但是编译时不会报错,运行时会报类型转换错误,这是因为方法返回的是一个实现接口AI的代理对象,而不是一个A类型的对象了:
A a = (A)BaseSPIManager.getProvider("test.A");
4.9.10 声明式事务和可编程事务混合使用
通过使用声明式的事务,开发人员无需在代码中再嵌入事务管理的代码。如果用户即声明了事务,又在代码中嵌入了事务管理代码,那么事务管理框架根据事务类型进行相应的处理,具体的处理方法见下表:
| 方法实现中开启事务类型 | |||
方法声明事 务类型 | NEW_TRANSACTION | REQUIRED_TRANSACTION | MAYBE_TRANSACTION | NO_TRANSACTION |
NEW_TRANSACTION | 屏蔽声明的事务,程序中开启一个新事务 | 使用声明的事务 | 使用声明的事务 | 屏蔽声明的事务,程序在没有事务的环境下运行 |
REQUIRED_TRANSACTION | 屏蔽声明的事务,程序中开启一个新事务 | 使用声明的事务 | 使用声明的事务 | 屏蔽声明的事务,程序在没有事务的环境下运行 |
MAYBE_TRANSACTION | 如果声明的事务存在,屏蔽声明的事务,程序中开启一个新事务 | 如果声明的事务存在,则使用声明的事务,否则开启一个新的事务 | 如果声明的事务存在,则使用声明的事务,否则不需声明事务 | 如果声明的事务存在,屏蔽声明的事务,程序在没有事务的环境下运行 |
NO_TRANSACTION | 程序中开启一个新事务 | 程序中开启一个新事务 | 程序在没有事务的环境下运行 | 程序在没有事务的环境下运行 |
作为使用事务的一个原则,系统中不应该出现同一个方法中既使用声明式事务又在代码中编写事务管理代码的情况,这样会导致达不到预期的事务管理的效果。
bboss项目下载列表 在sourceforge访问地址为:
https://sourceforge.net/project/showfiles.php?group_id=238653