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

来源:互联网 发布:网络直播行业报告 编辑:程序博客网 时间:2024/05/16 10:47

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

下面来看一下如何将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";@Overridepublic 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;}@Overridepublic 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";@Overridepublic int countAll() {return getJdbcTemplate().queryForInt(COUNT_ALL_SQL);}/** * 这里表示了如何获取主键自增值 */@Overridepublic 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;}@Overridepublic void save(final UserModel user) {TransactionTemplate  transactionTemplate=TransactionTemplateUtils.getDefaultTransactionTemplate(txManager);transactionTemplate.execute(new TransactionCallbackWithoutResult(){@Overrideprotected 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());}});}@Overridepublic 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;}@Overridepublic void save(final AddressModel address) {TransactionTemplate transactionTemplate=TransactionTemplateUtils.getDefaultTransactionTemplate(txManager);transactionTemplate.execute(new TransactionCallbackWithoutResult(){@Overrideprotected void doInTransactionWithoutResult(TransactionStatus arg0) {KeyHolder keyHolder=adressDAO.save(address);System.out.println(keyHolder.getKey().intValue());}});}@Overridepublic 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、测试

@Testpublic 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 0
原创粉丝点击