Spring管理事物应用到实际的项目中--编程式事物

接着上一篇博客来写。。。

下面来看一下如何将Spring管理事物应用到实际的项目中,为了简化实现,这里只定义最简单的模型对象和不完整的DAO和Service层接口

1、定义项目中的模型对象,这里使用用户模型和用户的地址模型:模型对象一般放在model包里

public class UserModel {
	private int id;
	private String user_name;
	private String password;
	private AddressModel address;
    省略getter和setter方法

public class AddressModel {

	private int id;
	private String province;
	private String city;
	private String street;
	private int userid;
	省略getter和setter方法

2.1、定义DAO层接口    DAO层实现具体的数据访问逻辑,屏蔽对数据访问技术造成的差异

package com.spring.DAO;
public interface IUserDAO {
	public KeyHolder save(UserModel user);
	public int countAll();
}

package com.spring.DAO;
public interface IAdressDAO {
	public KeyHolder save(AddressModel address);
	public int countAll();
}

2.2、DAO层实现

package com.spring.DAOImpl;
public class UserJdbcDAOImpl extends NamedParameterJdbcDaoSupport implements IUserDAO{
	private final String INSERT_SQL="insert into td(user_name,password)values(:user_name,:password)";
	private final String COUNT_ALL_SQL="select count(*)from td";
	@Override
	public KeyHolder save(UserModel user) {
		KeyHolder keyHolder=new GeneratedKeyHolder();
		/**
		 * SqlParameterSource:可以使用SqlParameterSource实现作为来实现为命名参数设值,
		 * 默认有MapSqlParameterSource和BeanPropertySqlParameterSource实现;
		 * MapSqlParameterSource实现非常简单,只是封装了java.util.Map;
		 * 而BeanPropertySqlParameterSource封装了一个JavaBean对象,通过JavaBean对象属性来决定命名参数的值。
		 */
		SqlParameterSource paramSource=new BeanPropertySqlParameterSource(user);
		/**
		 * 设置如何获取自增主键值
		 */
		getNamedParameterJdbcTemplate().update(INSERT_SQL, paramSource,keyHolder,new String[]{"id"});
		return keyHolder;
	}
	@Override
	public int countAll() {
		return getJdbcTemplate().queryForInt(COUNT_ALL_SQL);
	}
}
package com.spring.DAOImpl;
public class AddressJdbcDAOImpl extends NamedParameterJdbcDaoSupport implements IAdressDAO{
	private final String INSERT_SQL="insert into address(province,city,street,userid) values(:province,:city,:street,:userid)";
	private final String COUNT_ALL_SQL="select count(*)from address";
	@Override
	public int countAll() {
		return getJdbcTemplate().queryForInt(COUNT_ALL_SQL);
	}
	/**
	 * 这里表示了如何获取主键自增值
	 */
	@Override
	public KeyHolder save(AddressModel address) {
		KeyHolder keyHolder=new GeneratedKeyHolder();
		SqlParameterSource paramSource=new BeanPropertySqlParameterSource(address);
		/**
		 * 注意下面的参数列表
		 */
		getNamedParameterJdbcTemplate().update(INSERT_SQL, paramSource,keyHolder,new String[]{"id"});
		return keyHolder;
	}
}

3.1、定义Service层接口,一般使用IxxxServeice命名,Service类对象的是业务类

package com.spring.Service;
public interface IUserService {
	public void save(UserModel user);
	public int countAll();
}

package com.spring.Service;
public interface IAdressService {
	public void save(AddressModel address);
	public int countAll();
}

3.2、定义Service层实现,一般使用“×××ServiceImpl”或“×××Service”命名:

package com.spring.serviceImpl;
public class UserServiceImpl implements IUserService{

	private IUserDAO userDAO;
	private IAdressService adressService;
	public void setAdressService(IAdressService adressService) {
		this.adressService = adressService;
	}
	private PlatformTransactionManager txManager;
	public IUserDAO getUserDAO() {
		return userDAO;
	}
	public void setUserDAO(IUserDAO userDAO) {
		this.userDAO = userDAO;
	}
	public PlatformTransactionManager getTxManager() {
		return txManager;
	}
	public void setTxManager(PlatformTransactionManager txManager) {
		this.txManager = txManager;
	}
	@Override
	public void save(final UserModel user) {
		TransactionTemplate  transactionTemplate=TransactionTemplateUtils.getDefaultTransactionTemplate(txManager);
		transactionTemplate.execute(new TransactionCallbackWithoutResult(){
			@Override
			protected void doInTransactionWithoutResult(TransactionStatus status) {
				/**
				 * 如何获取自增主键值
				 */
				KeyHolder key=userDAO.save(user);
				System.out.println(key.getKey().intValue());
				user.getAddress().setUserid( key.getKey().intValue());
				System.out.println(user.getAddress().getUserid());
				System.out.println(user.getAddress().getProvince());
				adressService.save(user.getAddress());
			}
		});
	}
	@Override
	public int countAll() {
		return userDAO.countAll();
	}
}


package com.spring.serviceImpl;
public class AddressServeiceImpl implements IAdressService{

	private IAdressDAO adressDAO;
	private PlatformTransactionManager txManager;
	public void setAdressDAO(IAdressDAO adressDAO) {
		this.adressDAO = adressDAO;
	}
	public void setTxManager(PlatformTransactionManager txManager) {
		this.txManager = txManager;
	}
	@Override
	public void save(final AddressModel address) {
		TransactionTemplate transactionTemplate=TransactionTemplateUtils.getDefaultTransactionTemplate(txManager);
		transactionTemplate.execute(new TransactionCallbackWithoutResult(){

			@Override
			protected void doInTransactionWithoutResult(TransactionStatus arg0) {
				KeyHolder keyHolder=adressDAO.save(address);
				System.out.println(keyHolder.getKey().intValue());
			}
		});
	}
	@Override
	public int countAll() {
		return adressDAO.countAll();
	}
}
4、定义TransactionTemplateUtils,用于简化获取TransactionTemplate模板类,工具类一般放在util包中:

package com.spring.util;
public class TransactionTemplateUtils {
	public static TransactionTemplate getTransactionTemplate(PlatformTransactionManager txManager,
			int propagationBehavior,
			int isolationLevel){
		TransactionTemplate transactionTemplate=new TransactionTemplate(txManager);
		transactionTemplate.setPropagationBehavior(propagationBehavior);
		transactionTemplate.setIsolationLevel(isolationLevel);
		return transactionTemplate;
	}
	/**
	 * 
	 * @param txManager
	 * @return  getDefaultTransactionTemplate用于获取传播行为为PROPAGATION_REQUIRED,隔离级别为ISOLATION_READ_COMMITTED的模板类。
	 */
	public static TransactionTemplate getDefaultTransactionTemplate(PlatformTransactionManager txManager){
		return getTransactionTemplate(txManager,TransactionDefinition.PROPAGATION_REQUIRED,
				TransactionDefinition.ISOLATION_READ_COMMITTED);
	}
}

6、配置文件

<!-- datasource for oracle -->
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource"
		destroy-method="close">
		<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"></property>
		<property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"></property>
		<property name="username" value="scott"></property>
		<property name="password" value="123"></property>
	</bean>

	<!-- DAO层配置定义 -->
	<bean id="userDAO" class="com.spring.DAOImpl.UserJdbcDAOImpl">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<bean id="txManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<!-- service层配置定义 -->
	<bean id="userService" class="com.spring.serviceImpl.UserServiceImpl">
		<property name="userDAO" ref="userDAO"></property>
		<property name="txManager" ref="txManager"></property>
		<property name="adressService" ref="addressService"></property>
	</bean>

	<bean id="addressDAO" class="com.spring.DAOImpl.AddressJdbcDAOImpl">
	<property name="dataSource" ref="dataSource"></property>
	</bean>

	<bean id="addressService" class="com.spring.serviceImpl.AddressServeiceImpl">
		<property name="adressDAO" ref="addressDAO"></property>
		<property name="txManager" ref="txManager"></property>
	</bean>	

8、准备测试需要的表创建语句,这里我只创建了address表,因为之前已经创建过用户表在创建表时我实现了主键自增,所以同时要创建序列和引擎

package com.spring.test;
public class springTransactionTest {

	/**
	 * 创建address表
	 */
	public static final String CREATE_ADDRESS_TABLE_SQL="create table address(id int,province varchar2(40),city varchar2(100),"
			+ "street varchar2(100) ,userid int,primary key (id))";
	
	/**
	 * address:创建序列
	 */
	public static final String CREAT_SQU="create sequence se start with 1"
			+ "increment by 1 minvalue 1 maxvalue 999999 nocycle nocache";
	/**
	 * address:实现主键自增
	 */
	public static final String KEY_INCRE_SQL="insert into address(id) values (se.NEXTVAL)";
	
	/**
	 * address:创建引擎
	 */
	public static final String TRIGGER_SQL="create  trigger trie before insert on address for each row begin select se.NEXTVAL into :new.id from dual;end;";


9、测试

@Test
	public void test() {
		ApplicationContext ctx=new ClassPathXmlApplicationContext("/applicationContext.xml");
		DataSource dataSource=(DataSource) ctx.getBean("dataSource");
		JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);
		IUserService userService=(IUserService) ctx.getBean("userService");
		
		IAdressService addressService=(IAdressService) ctx.getBean("addressService");
		/**
		 * 创建表、序列、主键自增,引擎,之前一直在触发的时候出错
		 */
		
		jdbcTemplate.execute(CREATE_ADDRESS_TABLE_SQL);
		jdbcTemplate.execute(CREAT_SQU);
		jdbcTemplate.execute(KEY_INCRE_SQL);
		jdbcTemplate.execute(TRIGGER_SQL);
		
		UserModel user=createDefaultUserModel();
		userService.save(user);
	}
	private  UserModel createDefaultUserModel(){
		UserModel user=new UserModel();
		user.setUser_name("mk");
		user.setPassword("000");
		
		AddressModel address=new AddressModel();
		address.setProvince("zhejiang");
		address.setCity("jinhua");
		address.setStreet("hel");
		user.setAddress(address);
		return user;
	}

从Spring容器中获取Service层对象,调用Service层对象持久化对象,大家有没有注意到Spring事务全部在Service层定 义,
为什么会在Service层定义,而不是Dao层定义呢?这是因为在服务层可能牵扯到业务逻辑,而每个业务逻辑可能调用多个Dao
层方法,为保证这些 操作的原子性,必须在Service层定义事务。


Service层的事物管理相当令人头疼,而且是侵入式的,如何消除这些冗长的代码呢,这就需要spring声明式的事物支持。
在实现这一节的时候,我碰到的主要问题是创建表时关于引擎的问题,还有就是如何获得user表中的id然后插入到address表
中,后来我摸索了很久终于知道如何获取自增的主键值了,这了在dao层和service层中一定要搞清楚user表和address中字段
关系。
我参考的博客上面还介绍了事物的属性并举例实现,我还没弄太明白,所以没实现。


下一篇博客中我将展示以下我的声明式事物的实现

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值