??xml version="1.0" encoding="utf-8" standalone="yes"?>
原文出处:
http://www.javaeye.com/topic/11190
spring自徏事务理模块。而且q个事务理是一个抽象设计,可以应用到很多场合,包括普通的DataSourceQjtaQjms和hibernate上?/font>
要正用spring的事务,首先需要了解spring在事务设计上的一些概?
l观spring事务Q围l着两个核心PlatformTransactionManager和TransactionStatus
PlatformTransactionManager直译q来是q_相关事务Q这里的q_指的是“事务源”,包括刚才我说的DataSourceQjta{等。这些无一不是一个事务源。广义的_凡是可以完成事务性操作的对象Q都可以设计出相对应的PlatformTransactionManagerQ只要这个事务源支持commitQrollback和getTransaction语意?/font>
查看spring代码Q可以发现这些manager实现事务Q就是调用事务源的事务操作方?/font>
比如
HibernateTransactionManager
代码
jdbc 的DataSourceTransactionManager
代码
那么PlatformTransactionManager以什么依据处理事务呢Q?
是TransactionStatus
查看api发现q个接口有三个方?
isNewTransaction() QisRollbackOnly()QsetRollbackOnly()
PlatformTransactionManager是Ҏ前两个方法决定是否要创徏一个新事务Q是要递交q是回滚。至于第三个Ҏ是改变事务当前状态的Q很多地斚w要用刎ͼ偏偏PlatformTransactionManager自n好像不怎么用,毕竟事务状态的改变是由E序员代码决定的Q不需要一个manager多管闲事?/font>
ȝ上面所说的Qspring的事务由PlatformTransactionManager理Qmanager最后调用事务源的方法来实现一个事务过E。而manager通过TransactionStatus 来决定如何实现?
接下去说spring事务中的TransactionTemplate和TransactionInterceptor
TransactionTemplate其实和spring中其他的template的作用类|起到化简代码的作用,不要被它那么长的名字吓倒了Q事实上q个templateq不是什么非常核心的对象。如果比较学I派的,可以ȝ看template设计模式Q在此就不再Ҏ赘述了?
Z么要有TransactionTemplateQ先来看看如果没有TransactionTemplateQ我们的代码该怎么?/font>
先来看看spring reference中的一D代?
代码
q是直接使用transactionManager的例子,可以看到真正执行business logic 的地Ҏ在try当中那段Q前后的代码都是Z完成事务理的。如果每个business logic都要写上那么一D,我肯定是疯了。我们翻出TransactionTemplate的代码看看他怎么化简了我们的代码
代码
同上面的代码如出一辙,前后是事务处理代码,当中那段result = action.doInTransaction(status);是我们的应用代码。至于action是什么,全看各位的需要了。但是有一点要主要Q如果利用TransactionTemplateQ那么他不管你扔Z么异帔R会回滚事务,但是回滚的是哪个事务呢?l箋挖代?
代码
真相大白Q是对template所持有的某个transactionManagerq行回滚。所以如果你的应用代码用的是事务源a的一些资源,比如到服务器a的一个datasourceQ但是你的transactionManager理的是另一些资源,比如服务器b的一个datasourceQ代码铁定不会正常运?
特别是在一些多事务源的E序里,q点千万不能搞错。如果多个事务源之间要完成全局事务Q还是老老实实用分布式事务管理服务吧QjtaQ?/font>
那么TransactionInterceptor是干什么的Q这个是spring 的声明式事务的支持方式。因为用TransactionTemplate要硬~码Q而且调整事务{略很麻烦(不是说不能调。D个例子原来程序抛出异常A需要回滚,现在不需要要Q我可以把a catch吃掉。这时候template׃会回滚了。但是每ơ调整都要重写编码。)而用TransactionInterceptor可以将q些调整写在配置中。我们再来挖TransactionInterceptor的代?/font>
代码
万变不离其宗?
所以用spring的事务管理需要作q些?
1Q设|好事务源,比如DataSourceQhibernate的session。如果有多个事务源要考虑他们之间是否有全局事务Q如果有Q老老实实用jtaQ否则就需要自己写一个manager?
2Q设|managerQ根据你的事务源选择对应的PlatformTransactionManager
3Q选择实现事物的方式,用templateq是interceptor。用template代码直观点,但是template所辖的manager和你应用代码所用的事务源要一致。如果用interceptor千万注意Q一定要调用interceptor那个beanQ而不是原始的那个target。在坛子上我已经看到臛_有两个朋友说spring事物不v作用Q从配置和代码上看都正确Q这时要好好查查Q调用的bean是哪一个?
4Q这个是设计问题了,推荐事务处于一个较高层ơ,比如service上的某个函数Q而底层的dao可以不考虑事务Q否则可能会出现事务嵌套Q增加程序复杂度?/font>
下一个项目的权限理会比较复杂,以前没学q这斚w的知识。从Acegi开始吧Q如果够用最好?br />
6. JBoss JBoss的CacheQAppServer的cluster斚w是我比较感兴的地方Q想试一下JBoss应用服务?br />
7. 满一定条?比如: q发?000个请?框架Web Application集部v
关于Spring属性编辑器详解
代码
但是Qƈ非Bean的属性都是这些常见的cdQ如果你的Bean需要注入一个自定义cd的属性,而又想n受IoC的好处,那么只得自己开qԌ提供一个自定义的PropertyEditor了? 下面Q分几个步骤来说明,定义一个自定义PropertyEditor的过E? 1)首先Q碰到的问题xQ要如何~辑自己的PropertyEditor,其实需要了解一点java.beans包的知识Q在该包中,有一个java.beans.PropertyEditor的接口,它定义了一套接口方法(12个)Q即通过q些Ҏ如何一个String变成内部的一个对象,q两个方法是比较重要的: a)setValue(Object value) 直接讄一个对象,一般不直接用该Ҏ讄属性对? b)setAsText(String text) 通过一个字W串来构造对象,一般在此方法中解析字符Ԍ构造一? cd象,调用setValue(Object)来完成属性对象设|操作? 2)实现所有的接口Ҏ是麻烦的Qjava.beans.PropertyEditorSupport 适时dQ一般情况下Q我们通过扩展q个方便cd可?
3)~写完后Q就是在Spring配置文g中注册该属性类型编辑器的问题,Spring提供了专门的注册工具c?
下面l出一个小例子Q例子先作一个简单描qͼ
代码
2.Address.java
代码
AddressPropertyEditor.java
代码
打开Spring配置文gQ添上这两个配置:
代码
|
以下举例Q?br />1、指定参数的情况Q?br /> <id name="id" unsaved-value="0">
<generator class="sequence">
<param name="sequence">SEQ_CHILD</param>
</generator>
</id>
使用的是sequenceQ适合oracle数据库;
2、对于sql server2000中的数据库子增字D?在配|文件用下列方法实玎ͼ
<id name="id" type="long" unsaved-value="0">
<column name="id" sql-type="numeric" not-null="true" />
<generator class="identity" />
</id>
q里主要?identity:代表由sql server2000数据库自己提供子增字D?如果要hibernate自己提供,则用increment关键字来实现
3、如果表中的主键用字W串cd:可以用hibernate自己提供的方法实C键唯一:
<id name="id" type="string" unsaved-value="null">
<column name="cid" sql-type="char(32)" not-null="true" />
<generator class="uuid.hex" />
</id>
使用的是uuid.hex: 采用128位的法来生成一?2位字W串。最通用的一U方式。适用于所有数据库?/font>
重要的知识点:
1. 如果有部门表,有员工表,员工表中有dep_id,则表部门cd员工cLone-to-many的关p?
可以使用: ( 在部门类department中用下?
Departmentc?
/** 部门的所有员工 ?*/
private Set staffs = new TreeSet();
xml的文?
<set name="staffs" >
<key column="dep_id"/>
<one-to-many class="hbp.sys.data.Staff"/>
</set>
如果是list,需要用索引<index> </index>,具体其中的含?不是很明?待以后研I?br />
2. 如果部门要有一个负责h,即部门表(tb_department)中有一个字D?staff_id.
那么表示部门和负责h之间的关pLmany-to-one的关p?br /> Departmentc?
/** 部门负责人id */
private Staff staff;
xml 文g
<many-to-one name="staff" class="hbp.sys.data.Staff" column="staff_id"/>
3. 多对多关p?一般我们是做一个中间关联表.我用角色和权限做了个例子,
Right(id,name) Role(id,name) 中间?tb_role_right(role_id,right_id)
RightcM有一个Role的集?private Set roles=new TreeSet();
RolecM也有一个Right的集?private Set rights=new TreeSet();
则两者是明显的多对多关系.使用many-to-many来实?
xml文g?br /> right.hbm.xml:如下:
<set name="roles" table="tb_role_right" cascade="all">
<key column="right_id"/>
<many-to-many column="role_id" class="hbp.sys.data.Role"/>
</set>
role.hbm.xml文g中类?
<set name="rights" table="tb_role_right" cascade="all">
<key column="role_id"/>
<many-to-many column="right_id" class="hbp.sys.data.Right"/>
</set>
4. 几个值得注意的问?
a)在xml?映射文g?写类的名字时一定用cȝ全名:??cd?(hbp.sys.data.Staff),q个错误使我费了半天?:(
b)我在写实现基本DAO操作?写了
session.delete("from Right as right where right.id="+id);
E序L报错,我折腾了半天,跟踪到底,才恍然大?hibernate在解析sql语句的时候把
其中的right,当成了数据库中的双?"保留?),?q种关键?不能随便用啊,:)
5. hibernate中HQL语言的查询根据你的sql的不同而返回不同的对象cd.
如果你用session.find(String hql)
一般会q回一个List,?from Staff staff;q回的是包含所有的员工对象的集?br /> 如你的hql?select count(*) from Staff staff;则返回的是一个Integer对象
如果你用的hql?select count(distinct staff.name),count(*) from Staff staff;则返回的是一个Object
即Object[],需要先把他转换成Object[],然后在取[0],[1].
q种设计我不知道hibernate是如何处理的,感觉既好也不?好的是可以用一个find获得L查询
不好在于Ҏhql来处理返回结?Ҏ出错.