本文共 8099 字,大约阅读时间需要 26 分钟。
Spring学习笔记(
17
)----使用Spring注解方式管理事务
--------------------------------------------------
使用Spring+JDBC集成步骤如下:
*配置数据源,例如:
Xml代码
1
.<bean id=
"dataSource"
class
=
"org.apache.commons.dbcp.BasicDataSource"
destroy-method=
"close"
>
2
. <property name=
"driverClassName"
value=
"com.mysql.jdbc.Driver"
/>
3
. <property name=
"url"
value=
"jdbc:mysql://localhost:3306/test"
/>
4
. <property name=
"username"
value=
"root"
/>
5
. <property name=
"password"
value=
"123456"
/>
6
. <!-- 连接池启动时的初始值 -->
7
. <property name=
"initialSize"
value=
"1"
/>
8
. <!-- 连接池的最大值 -->
9
. <property name=
"maxActive"
value=
"100"
/>
10
. <!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢释放一部分,一直减少到maxIdle为止 -->
11
. <property name=
"maxIdle"
value=
"2"
/>
12
. <!-- 最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请去一些连接,以免洪峰来时来不及申请 -->
13
. <property name=
"minIdle"
value=
"1"
/>
14
. </bean>
*配置事务,配置事务时,需要在xml配置文件中引入用于声明事务的tx命名空间,事务的配置有两种方式:注解方式和基于XML配置的方式
下面演示下使用Spring注解方式管理事务
首先在配置文件中配置Spring提供的事务管理器
Xml代码
1
.<bean id=
"txManager"
class
=
"org.springframework.jdbc.datasource.DataSourceTransactionManager"
>
2
. <!-- 指定数据源 -->
3
. <property name=
"dataSource"
ref=
"dataSource"
/>
4
. </bean>
由于会使用注解方式,因此我们要打开注解处理器,对注解进行解析
Xml代码
1
.<tx:annotation-driven transaction-manager=
"txManager"
/>
这样我们的配置文件配置完成,下面我们在Mysql中建立一张表,
Sql代码
1
.create table users
2
.(
3
. id
int
(
11
) not
null
auto_increment,
4
. username varchar(
20
) not
null
,
5
. primary key (id)
6
.)
根据数据库,我们创建javabean
Java代码
1
.
package
com.szy.spring.bean;
2
.
/**
3. * @author coolszy
4. * @time Dec 6, 2009 2:13:33 PM
5. */
6
.
public
class
User
7
.{
8
.
private
int
id;
9
.
private
String username;
10
.
public
int
getId()
11
. {
12
.
return
id;
13
. }
14
.
public
void
setId(
int
id)
15
. {
16
.
this
.id = id;
17
. }
18
.
public
String getUsername()
19
. {
20
.
return
username;
21
. }
22
.
public
void
setUsername(String username)
23
. {
24
.
this
.username = username;
25
. }
26
.}
然后创建DAO接口,在DAO中提供几个方法:
Java代码
1
.
package
com.szy.spring.dao;
2
.
3
.
import
java.util.List;
4
.
5
.
import
com.szy.spring.bean.User;
6
.
7
.
public
interface
UserDAO
8
.{
9
.
public
void
save(User user);
10
.
public
void
update(User user);
11
. Public User getUser(
int
id);
12
.
public
void
delete(
int
id);
13
.
public
List<User> getAllUsers();
14
.}
实现这个接口
Java代码
1
.
package
com.szy.spring.dao.impl;
2
.
3
.
import
java.util.List;
4
.
5
.
import
com.szy.spring.bean.User;
6
.
import
com.szy.spring.service.UserService;
7
.
8
.
/**
9. * @author coolszy
10. * @time Dec 6, 2009 2:19:22 PM
11. */
12
.
public
class
UserDAOImpl
implements
UserDAO
13
.{
14
.
15
.
public
void
delete(
int
id)
16
. {
17
.
18
. }
19
.
20
.
public
List<User> getAllUsers()
21
. {
22
.
return
null
;
23
. }
24
.
25
.
public
User getUser(
int
id)
26
. {
27
.
28
. }
29
.
30
.
public
void
save(User user)
31
. {
32
.
33
. }
34
.
35
.
public
void
update(User user)
36
. {
37
.
38
. }
39
.
40
.}
下面把这个类交给Spring管理
Xml代码
1
.<bean id=
"userDAO"
class
=
"com.szy.spring.dao.impl.UserDAOImpl"
/>
由于要通过数据源对表进行操作,因此在DAO中添加数据源。
Java代码
1
.
private
DataSource dataSource;
2
.
3
.
public
void
setDataSource(DataSource dataSource)
4
. {
5
.
this
.dataSource = dataSource;
6
. }
然后在配置文件中进行配置
Xml代码
1
.<bean id=
"userDAO"
class
=
"com.szy.spring.service.impl.UserDAOImpl"
>
2
. <property name=
"dataSource"
ref=
"dataSource"
/>
3
. </bean>
这样我们就把数据源注入到类中。
在UserDAOImpl类中我们提供了dataSource,这样我们就可以对数据库进行操作,但是不推荐直接使用dataSource,建议使用JdbcTemplate
Java代码
1
.
private
JdbcTemplate jdbcTemplate;
2
.
public
void
setDataSource(DataSource dataSource)
3
. {
4
.
//this.dataSource = dataSource;
5
.
this
.jdbcTemplate=
new
JdbcTemplate(dataSource);
6
. }
下面我们使用jdbcTemplate对数据库进行增删改查,详细代码见附件。
Java代码
1
.
package
com.szy.spring.dao.impl;
2
.
3
.
import
java.util.List;
4
.
5
.
import
javax.sql.DataSource;
6
.
7
.
import
org.springframework.jdbc.core.JdbcTemplate;
8
.
9
.
import
com.szy.spring.bean.User;
10
.
import
com.szy.spring.dao.UserDAO;
11
.
12
.
/**
13. * @author coolszy
14. * @time Dec 6, 2009 2:19:22 PM
15. */
16
.
public
class
UserDAOImpl
implements
UserDAO
17
.{
18
.
//private DataSource dataSource;
19
.
private
JdbcTemplate jdbcTemplate;
20
.
public
void
setDataSource(DataSource dataSource)
21
. {
22
.
//this.dataSource = dataSource;
23
.
this
.jdbcTemplate=
new
JdbcTemplate(dataSource);
24
. }
25
.
26
.
public
void
delete(
int
id)
27
. {
28
. jdbcTemplate.update(
"delete from users where id=?"
,
new
Object[]{id},
29
.
new
int
[]{java.sql.Types.INTEGER});
30
. }
31
.
32
.
public
List<User> getAllUsers()
33
. {
34
.
return
(List<User>)jdbcTemplate.query(
"select * from users"
,
new
UserRowMapper());
35
. }
36
.
37
.
public
User getUser(
int
id)
38
. {
39
.
return
(User)jdbcTemplate.queryForObject(
"select * from users where id=?"
,
new
Object[]{id},
40
.
new
int
[]{java.sql.Types.INTEGER},
new
UserRowMapper());
41
.
42
. }
43
.
44
.
public
void
save(User user)
45
. {
46
. jdbcTemplate.update(
"insert into users(username) values(?)"
,
new
Object[]{user.getUsername()},
47
.
new
int
[]{java.sql.Types.VARCHAR});
48
.
49
. }
50
.
51
.
public
void
update(User user)
52
. {
53
. jdbcTemplate.update(
"update users set username=? where id=?"
,
new
Object[]{user.getUsername(),user.getId()},
54
.
new
int
[]{java.sql.Types.VARCHAR, java.sql.Types.INTEGER});
55
.
56
. }
57
.
58
.}
编写测试代码,代码运行正常。
在我们实现的每个方法中如delete()方法,如果delete方法是这样
Java代码
1
.
public
void
delete(
int
id)
2
. {
3
. jdbcTemplate.update(
"delete from users where id=?"
,
new
Object[]{id},
4
.
new
int
[]{java.sql.Types.INTEGER});
5
.jdbcTemplate.update(
"delete from users where id=?"
,
new
Object[]{id},
6
.
new
int
[]{java.sql.Types.INTEGER});
7
.
8
. }
9
.
这样每条语句都会在各自的事务中执行,并不能保证在同一使用中执行,为了保证在同一事务中执行,我们应使用Spring容器提供的声明事务,我们在UserDAOImpl 类上加入
@Transactional
,表示该类受Spring事务管理。如果该类中每个方法不需要事务管理,如getUser方法,则在该方法前加入
Java代码
1
.
@Transactional
(propagation=Propagation.NOT_SUPPORTED)
PS:在上面的配置文件中我们在配置文件中指明了驱动类等信息,如果我们想写在配置文件中要怎么配置能,首先我们编写配置文件,
Jdbc.properties代码
1
.driverClassName=com.mysql.jdbc.Driver
2
.url=jdbc\:mysql\:
//localhost\:3306/test
3
.username=root
4
.password=
123456
5
.initialSize=
1
6
.maxActive=
100
7
.maxIdle=
2
8
.minIdle=
1
然后Spring的配置文件需进行如下配置:
Xml代码
1
.<context:property-placeholder location=
"classpath:jdbc.properties"
/>
2
. <bean id=
"dataSource"
class
=
"org.apache.commons.dbcp.BasicDataSource"
destroy-method=
"close"
>
3
. <property name=
"driverClassName"
value=
"${driverClassName}"
/>
4
. <property name=
"url"
value=
"${url}"
/>
5
. <property name=
"username"
value=
"${username}"
/>
6
. <property name=
"password"
value=
"${password}"
/>
7
. <property name=
"initialSize"
value=
"${initialSize}"
/>
8
. <property name=
"maxActive"
value=
"${maxActive}"
/>
9
. <property name=
"maxIdle"
value=
"${maxIdle}"
/>
10
. <property name=
"minIdle"
value=
"${minIdle}"
/>
11
. </bean>
这样就可以从属性文件中读取到配置信息。
Spring学习笔记(
18
)----使用Spring配置文件实现事务管理
-------------------------------------------------------
由于我们要拦截UserDAOImpl中的方法,因此我们需要在配置文件中配置信息,在配置文件中使用了AOP技术来拦截方法。
Xml代码
1
.<aop:config>
2
. <aop:pointcut id=
"transactionPointcut"
expression=
"execution(* com.szy.spring.dao.impl..*.*(..))"
/>
3
. <aop:advisor advice-ref=
"txAdvice"
pointcut-ref=
"transactionPointcut"
/>
4
. </aop:config>
5
. <tx:advice id=
"txAdvice"
transaction-manager=
"txManager"
>
6
. <tx:attributes>
7
. <!-- 如果连接的方法是以get开头的方法,则不使用事务 -->
8
. <tx:method name=
"get*"
read-only=
"true"
propagation=
"NOT_SUPPORTED"
/>
9
. <tx:method name=
"*"
/>
10
. </tx:attributes>
11
. </tx:advice>
这样Spring就能对这个类进行事务管理。
下面我们测试下数据库操作是否在同一事务中执行。
假设我们的delete方法如下:
Java代码
1
.
public
void
delete(
int
id)
2
. {
3
. jdbcTemplate.update(
"delete from users where id=?"
,
new
Object[]{id},
4
.
new
int
[]{java.sql.Types.INTEGER});
5
. jdbcTemplate.update(
"delete from users1 where id=10"
);
6
. }
在第二条删除语句中,users1表是不存在的,如果两次update语句是在两个事务中执行,则第一条能成功执行,并且数据库中该id的记录已经被删除,而第二条由于不存在该表不能正常删除。如果在同一事务中执行,由于第二条update出错,数据库中不能删除任何记录。
测试代码:
Java代码
1
.
@Test
2
.
public
void
testDelete()
3
. {
4
. userDAO.delete(
5
);
5
. }
程序报错,同时id=
5
的记录没有被删除。如果我们把配置文件中关于事务配置的信息给注释掉,再次测试,程序同样报错,但是id=
5
的记录被成功删除掉,这说明这两条update语句是在两个不同的事务中运行。
PS:在平时开发中,Spring团队建议使用注解的方式进行配置,这样配置文件显得精简,同时也会做到精确控制。
转载地址:http://rsfbi.baihongyu.com/