java 编程式事务,Spring事务之编程式事务

一.Spring对编程式事务的支持

Spring中的事务分为物理事务和逻辑事务;

物理事务:就是底层数据库提供的事务支持,如JDBC或JTA提供的事务;

逻辑事务:是Spring管理的事务,不同于物理事务,逻辑事务提供更丰富的控制,而且如果想得到Spring事务管理的好处,必须使用逻辑事务,因此在Spring中如果没特别强调一般就是逻辑事务;

逻辑事务即支持非常低级别的控制,也有高级别解决方案:

低级别解决方案:使用工具类获取连接(会话)和释放连接(会话),如Spring中使用DataSourceUtils ,Hibernate中使用SessionFactoryUtils,JPA中使用EntityManagerFactoryUtils

高级别解决方案:使用Spring提供的模板类,如JdbcTemplate、HibernateTemplate和JpaTemplate模板类等,而这些模板类内部其实是使用了低级别解决方案中的工具类来管理连接或会话

二.使用PlatformTransactionManager

applicationContext.xml

classpath:jdbc.properties

使用低级别解决方案来进行事务管理器测试:

@Test

public void testPlatformTransactionManager() {

DefaultTransactionDefinition def = new DefaultTransactionDefinition();

def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);

def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

TransactionStatus status = txManager.getTransaction(def);

Connection connection = DataSourceUtils.getConnection(dataSource);

try{

connection.prepareStatement(CREATE_TABLE_SQL).execute();

PreparedStatement pstmt = connection.prepareStatement(INSERT_SQL);

pstmt.setString(1, "test");

pstmt.execute();

connection.prepareStatement(DROP_TABLE_SQL).execute();

txManager.commit(status);

}catch(Exception ex){

status.setRollbackOnly();

txManager.rollback(status);

}finally{

DataSourceUtils.releaseConnection(connection, dataSource);

}

}

使用高级别方案JdbcTemplate****来进行事务管理器测试

@Test

public void testPlatformTransactionManager() {

DefaultTransactionDefinition def = new DefaultTransactionDefinition();

def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);

def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

TransactionStatus status = txManager.getTransaction(def);

try{

jdbcTemplate.execute(CREATE_TABLE_SQL);

jdbcTemplate.update(INSERT_SQL, "test");

}catch(Exception ex){

txManager.rollback(status);

}

txManager.commit(status);

}

三.使用TransactionTemplate

TransactionTemplate模板类用于简化事务管理,事务管理由模板类定义,而具体操作需要通过TransactionCallback回调接口或TransactionCallbackWithoutResult回调接口指定,通过调用模板类的参数类型为TransactionCallback或TransactionCallbackWithoutResult的execute方法来自动享受事务管理。

TransactionTemplate模板类使用的回调接口:

TransactionCallback:通过实现该接口的“T doInTransaction(TransactionStatus status) ”方法来定义需要事务管理的操作代码;

TransactionCallbackWithoutResult:继承TransactionCallback接口,提供“void doInTransactionWithoutResult(TransactionStatus status)”便利接口用于方便那些不需要返回值的事务操作代码。

TransactionTemplate 模板类使用

@Test

public void testTransactionTemplate(){

TransactionTemplate transactionTemplate = new TransactionTemplate(txManager);

transactionTemplate.execute(new TransactionCallbackWithoutResult() {

@Override

protected void doInTransactionWithoutResult(TransactionStatus arg0) {

jdbcTemplate.execute(CREATE_TABLE_SQL);

jdbcTemplate.update(INSERT_SQL, "test");

}

});

String COUNT_ALL = "select count(*) from test";

Number count = jdbcTemplate.queryForInt(COUNT_ALL);

Assert.assertEquals(1, count.intValue());

jdbcTemplate.execute(DROP_TABLE_SQL);

}

三.实际应用

模型对象

public class User implements java.io.Serializable{

/**

*

*/

private static final long serialVersionUID = 1L;

private Address address;

private Integer id;

private String name;

//省略get,set

}

public class Address implements java.io.Serializable{

/**

*

*/

private static final long serialVersionUID = 1L;

private String city;

private Integer id;

private String province;

private String street;

private Integer userId;

//省略get,set

}

Dao层接口及实现

public interface UserDao {

public void save(User user);

public int countAll();

}

package transaction.dao;

import java.util.HashMap;

import java.util.Map;

import org.springframework.jdbc.core.namedparam.NamedParameterJdbcDaoSupport;

import transaction.bean.User;

public class UserDaoImp extends NamedParameterJdbcDaoSupport implements UserDao{

private final String INSERT_SQL = "insert into user(name) values(:name)";

private final String COUNT_ALL_SQL = "select count(*) from user";

@Override

public void save(final User user) {

Map para = new HashMap();

para.put("name", user.getName());

getNamedParameterJdbcTemplate().update(INSERT_SQL, para);

}

@Override

public int countAll() {

return getJdbcTemplate().queryForInt(COUNT_ALL_SQL);

}

}

public interface AddressDao {

public void save(Address address);

public int countAll();

}

public class AddressDaoImp extends NamedParameterJdbcDaoSupport implements AddressDao{

private final String INSERT_SQL = "insert into address(province, city, street, user_id)" + "values(:province, :city, :street, :userId)";

private final String COUNT_ALL_SQL = "select count(*) from address";

@Override

public void save(Address address){

KeyHolder generatedKeyHolder = new GeneratedKeyHolder();

/*SqlParameterSource source = new BeanPropertySqlParameterSource(address);

getNamedParameterJdbcTemplate().update(INSERT_SQL, source, generatedKeyHolder);*/

Map para = new HashMap();

para.put("province", address.getProvince());

para.put("city", address.getCity());

para.put("street", address.getStreet());

para.put("userId", address.getUserId());

getNamedParameterJdbcTemplate().update(INSERT_SQL, para);

}

@Override

public int countAll() {

return getJdbcTemplate().queryForInt(COUNT_ALL_SQL);

}

}

Service****层接口及实现

public interface UserService {

public void save(User user);

public int countAll();

}

@Override

public void save(final User user){

TransactionTemplate transactionTemplate = TransactionTemplateUtils.getDefaultTransactionTemplate(txManager);

transactionTemplate.execute(new TransactionCallbackWithoutResult(){

@Override

protected void doInTransactionWithoutResult(TransactionStatus arg0) {

userDao.save(user);

user.getAddress().setUserId(user.getId());

try {

addressService.save(user.getAddress());

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

});

}

@Override

public int countAll() {

return userDao.countAll();

}

public interface AddressService {

public void save(Address address) throws Exception;

public int countAll();

}

public class AddressServiceImp implements AddressService{

private AddressDao addressDao;

private PlatformTransactionManager txManager;

public void setAddressDao(AddressDao addressDao) {

this.addressDao = addressDao;

}

public void setTxManager(PlatformTransactionManager txManager) {

this.txManager = txManager;

}

@Override

public void save(final Address address){

TransactionTemplate transactionTemplate = TransactionTemplateUtils.getDefaultTransactionTemplate(txManager);

transactionTemplate.execute(new TransactionCallbackWithoutResult(){

@Override

protected void doInTransactionWithoutResult(TransactionStatus arg0) {

addressDao.save(address);

}

});

}

@Override

public int countAll() {

return addressDao.countAll();

}

}

applicationContext.xml

classpath:jdbc.properties

TransactionTemplateUtils类

public class TransactionTemplateUtils {

private static TransactionTemplate getTransactionTemplate(

PlatformTransactionManager txManager, int propagationBehavior,

int isolationLevel) {

TransactionTemplate transactionTemplate = new TransactionTemplate(txManager);

transactionTemplate.setPropagationBehavior(propagationBehavior);

transactionTemplate.setIsolationLevel(isolationLevel);

return transactionTemplate;

}

public static TransactionTemplate getDefaultTransactionTemplate(PlatformTransactionManager txManager) {

return getTransactionTemplate(txManager,

TransactionDefinition.PROPAGATION_REQUIRED,

TransactionDefinition.ISOLATION_READ_COMMITTED);

}

}

三.事务属性

事务属性通过TransactionDefinition接口实现定义,主要有事务隔离级别、事务传播行为、事务超时时间、事务是否只读。

Spring提供TransactionDefinition接口默认实现DefaultTransactionDefinition,可以通过该实现类指定这些事务属性

事务隔离级别:用来解决并发事务时出现的问题,其使用TransactionDefinition中的静态变量来指定:

ISOLATION_DEFAULT:默认隔离级别,即使用底层数据库默认的隔离级别;

ISOLATION_READ_UNCOMMITTED:未提交读;

ISOLATION_READ_COMMITTED:提交读,一般情况下我们使用这个;

ISOLATION_REPEATABLE_READ:可重复读;

ISOLATION_SERIALIZABLE:序列化

事务传播行为:Spring管理的事务是逻辑事务,而且物理事务和逻辑事务最大差别就在于事务传播行为,事务传播行为用于指定在多个事务方法间调用时,事务是如何在这些方法间传播的,Spring共支持7种传播行为

Required:必须有逻辑事务,否则新建一个事务,使用PROPAGATION_REQUIRED指定,表示如果当前存在一个逻辑事务,则加入该逻辑事务,否则将新建一个逻辑事务

RequiresNew:创建新的逻辑事务,使用PROPAGATION_REQUIRES_NEW指定,表示每次都创建新的逻辑事务(物理事务也是不同的)

Supports:支持当前事务,使用PROPAGATION_SUPPORTS指定,指如果当前存在逻辑事务,就加入到该逻辑事务,如果当前没有逻辑事务,就以非事务方式执行

NotSupported:不支持事务,如果当前存在事务则暂停该事务,使用PROPAGATION_NOT_SUPPORTED指定,即以非事务方式执行,如果当前存在逻辑事务,就把当前事务暂停,以非事务方式执行

Mandatory:必须有事务,否则抛出异常,使用PROPAGATION_MANDATORY指定,使用当前事务执行,如果当前没有事务

Never:不支持事务,如果当前存在是事务则抛出异常,使用PROPAGATION_NEVER指定,即以非事务方式执行,如果当前存在事务,则抛出异常(IllegalTransactionStateException)

Nested:嵌套事务支持,使用PROPAGATION_NESTED指定,如果当前存在事务,则在嵌套事务内执行,如果当前不存在事务,则创建一个新的事务,嵌套事务使用数据库中的保存点来实现,即嵌套事务回滚不影响外部事务,但外部事务回滚将导致嵌套事务回滚

Nested和RequiresNew的区别:

1、 RequiresNew每次都创建新的独立的物理事务,而Nested只有一个物理事务;

2、 Nested嵌套事务回滚或提交不会导致外部事务回滚或提交,但外部事务回滚将导致嵌套事务回滚,而 RequiresNew由于都是全新的事务,所以之间是无关联的;

3、 Nested使用JDBC 3的保存点实现,即如果使用低版本驱动将导致不支持嵌套事务。

使用嵌套事务,必须确保具体事务管理器实现的nestedTransactionAllowed属性为true,否则不支持嵌套事务,如DataSourceTransactionManager默认支持,而HibernateTransactionManager默认不支持,需要我们来开启

事务超时:设置事务的超时时间,单位为秒,默认为-1表示使用底层事务的超时时间;

事务只读:将事务标识为只读,只读事务不修改任何数据;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值