修改applicationContext.xml文件,增加如下内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
2、初始化HibernateTransactionManager
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
xsi:schemaLocation="http://www.springframework.org/schema/beans
<
context:annotation-config
/>
<
context:component-scan
base-package
=
"com.fz.annotation"
/>
<
bean
class
=
"org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
>
<
property
name
=
"locations"
value
=
"classpath:jdbc.properties"
/>
</
bean
>
<
bean
id
=
"dataSource"
destroy-method
=
"close"
class
=
"org.apache.commons.dbcp.BasicDataSource"
>
<
property
name
=
"driverClassName"
value
=
"${jdbc.driverClassName}"
/>
<
property
name
=
"url"
value
=
"${jdbc.url}"
/>
<
property
name
=
"username"
value
=
"${jdbc.username}"
/>
<
property
name
=
"password"
value
=
"${jdbc.password}"
/>
</
bean
>
<!-- annotation方式管理hibernate的sessionFactory -->
<
bean
id
=
"sessionFactory"
class
=
"org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
>
<
property
name
=
"dataSource"
ref
=
"dataSource"
/>
<
property
name
=
"packagesToScan"
>
<
list
>
<
value
>com.fz.annotation.model</
value
>
</
list
>
</
property
>
<
property
name
=
"hibernateProperties"
>
<
props
>
<
prop
key
=
"hibernate.dialect"
>org.hibernate.dialect.MySQLDialect</
prop
>
<
prop
key
=
"hibernate.show_sql"
>true</
prop
>
<
prop
key
=
"hibernate.format_sql"
>true</
prop
>
</
props
>
</
property
>
</
bean
>
<
tx:annotation-driven
transaction-manager
=
"myTxManager"
/>
<
bean
id
=
"myTxManager"
class
=
"org.springframework.orm.hibernate3.HibernateTransactionManager"
>
<
property
name
=
"sessionFactory"
ref
=
"sessionFactory"
/>
</
bean
>
</
beans
>
|
这里需要配置一个HibernateTransactionManager的bean和<
tx:annotation-driven
transaction-manager
=
"myTxManager"
/>
3、在Service层使用事务管理
userServiceImpl.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
package
com.fz.annotation.service.impl;
import
javax.annotation.Resource;
import
org.springframework.stereotype.Service;
import
org.springframework.transaction.annotation.Transactional;
import
com.fz.annotation.dao.UserDao;
import
com.fz.annotation.model.User;
import
com.fz.annotation.service.UserService;
@Service
(
"userService"
)
public
class
UserServiceImpl
implements
UserService{
private
UserDao userDao;
@Transactional
public
void
userAdd(User user) {
userDao.userAdd(user);
}
public
UserDao getUserDao() {
return
userDao;
}
@Resource
(name=
"userDao"
)
public
void
setUserDao(UserDao userDao) {
this
.userDao = userDao;
}
}
|
注意:这里使用@Transactional注解来注明该方法需要使用到事务
userDaoImpl.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
package
com.fz.annotation.dao.impl;
import
javax.annotation.Resource;
import
org.hibernate.Session;
import
org.hibernate.SessionFactory;
import
org.springframework.stereotype.Repository;
import
com.fz.annotation.dao.UserDao;
import
com.fz.annotation.model.User;
@Repository
(
"userDao"
)
public
class
UserDaoImpl
implements
UserDao{
private
SessionFactory sessionFactory;
public
void
userAdd(User user) {
Session session = sessionFactory.getCurrentSession();
session.save(user);
}
public
SessionFactory getSessionFactory() {
return
sessionFactory;
}
@Resource
public
void
setSessionFactory(SessionFactory sessionFactory) {
this
.sessionFactory = sessionFactory;
}
}
|
4、测试
测试正常情况,结果一切正常。数据库也插入了数据
1
2
3
4
5
6
7
8
9
|
@Test
public
void
getProperties(){
ClassPathXmlApplicationContext ctx =
new
ClassPathXmlApplicationContext(
"applicationContext_aop.xml"
);
UserService userService = (UserService) ctx.getBean(
"userService"
);
User user =
new
User();
user.setId(
4
);
user.setUsername(
"test1"
);
userService.userAdd(user);
}
|
修改userDaoImpl.java,抛出一个异常。看看是否能回滚
在userDaoImpl.java的userAdd方法中抛出一个异常
1
2
3
4
5
|
public
void
userAdd(User user) {
Session session = sessionFactory.getCurrentSession();
session.save(user);
throw
new
RuntimeException(
"aa"
);
}
|
然后再次测试的时候,发现数据库中没有插入该条数据。依然是上一次的数据
5、事务的传播特性Propagation
所谓传播特性:也就是Transaction的产生过程,以及事务来了后怎么管理这个事务。
@Transactional注解有个属性:Propagation,Propagation是一个枚举类型,默认是REQUIRED,枚举的值如下:
REQUIRED(默认,最常用,重要)
Support a current transaction, create a new one if none exists.
如果此时执行了mothod1,而method1里面又调用了method2.假如method1里面已经有了Transaction,那么method2里面就不需要再创建新的Transaction了,method2会使用原来的这个Transaction。如果method1里面没有Transaction,则method2会新建一个Transaction
例如:
1
2
3
4
|
@Transactional
(propagation=Propagation.REQUIRED)
public
void
userAdd(User user) {
userDao.userAdd(user);
}
|
如果别的service调用userAdd的时候已经有了Transaction,则此时不会创建新的Transaction。如果调用的时候没有Transaction。则这里会新建一个Transaction
MANDATORY
Support a current transaction, throw an exception if none exists.
必须得有Transaction,没有则抛异常。
例如:如果把上面的REQUIRED改为MANDATORY,如果调用这个userAdd方法之前必须得有Transaction存在。否则则抛异常。
1
2
3
4
|
@Transactional
(propagation=Propagation.MANDATORY)
public
void
userAdd(User user) {
userDao.userAdd(user);
}
|
NESTED
Execute within a nested transaction if a current transaction exists, behave like PROPAGATION_REQUIRED else.
如果有一个Transaction(A)存在了,则暂停A。自己新建一个Transaction(B),等B执行完了,A才会继续执行。就是新建一个Transaction内嵌到原来的Transaction中。
NEVER
Execute non-transactionally, throw an exception if a transaction exists.
必须没有Transaction,如果有Transaction则抛异常。
NOT_SUPPORTED
Execute non-transactionally, suspend the current transaction if one exists.
必须不能有Transaction,如果有则挂起原来的Transaction,暂停原来的Transaction,执行当前方法内的Transaction后,原来的Transaction再继续。
REQUIRES_NEW
Create a new transaction, suspend the current transaction if one exists.
创建一个新Transaction,如果当前有Transaction。就将其挂起(暂停)
SUPPORTS
Support a current transaction, execute non-transactionally if none exists.
支持当前Transaction,如果当前有则有,当前没有则没有。