打开 Spring2.0管理Ibatis 文中所建的工程:ComposeIbatis
找到接口 IUserDao.java ,增加方法:public void addUserInfo(); 用于增加用户操作。其实现类:UserImpl.java 实现 addUserInfo() 方法,在业务类 UserService 中调用,而Struts的action调用业务类。所有改动如下:
一、IUserDao.java 加入方法:addUserInfo() :
- package com.test.dao;
- import java.util.List;
- public interface IUserDao {
- public List getUserInfo();
- public void addUserInfo();
- }
二、UserImpl.java 加入实现方法:addUserInfo() :
- ................
- public void addUserInfo() {
- UserModel umodel = new UserModel();
- umodel.setId("4");
- umodel.setName("lalala");
- umodel.setPassword("123456789");
- umodel.setState(1);
- this.getSqlMapClientTemplate().insert(StaticSqlString.getADD_USER(), umodel);
- this.getSqlMapClientTemplate().insert(StaticSqlString.getADD_USER(), umodel);
- }
- ...............
三、UserService.java 加入调用方法:addUser() :
- ....................
- public void addUser()throws DataAccessException{
- dao.addUserInfo();
- }
- .....................
四、Struts的Action类execute()方法改动为:
- ..........
- public String execute() throws Exception {
- String type = request.getParameter("type").toString();
- if(type.equals("1")){
- List list = new ArrayList();
- list = user.getUserInfo();
- this.setUserlist(list);
- }else{
- user.addUser();
- }
- return "testok";
- }
- ..........
五、index.jsp页面增加addUser按钮,更改为:
- <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
- <%@taglib uri="/struts-tags" prefix="s" %>
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
- <html>
- <head>
- <title>Test</title>
- </head>
- <body>
- <a href="/ComposeIbatis/user.action?type=1">Click Me(getList)</a>
- <br>
- <a href="/ComposeIbatis/user.action?type=2">Click Me(addUser)</a>
- </body>
- </html>
以上改动主要是希望在 index.jsp 中按下 addUser 按钮后, Action 会通过业务类调用数据层,在数据库中新增一条正确的数据。改动完成可以运行一下,然后查询DB查看是否新增成功。如新增成功,则通过DB管理器用sql语句删除新增数据,停止运行。
接下来人为制造一个数据库访问错误:打开 UserImpl.java 找到 addUserInfo 方法,将 this.getSqlMapClientTemplate().insert(StaticSqlString.getADD_USER(), umodel); 这句代码执行2次,这样一来由于第一次代码成功新增了一条合法数据数据,第二次再次新增同样的数据时,由于表字段ID的主键约束会发生约束错误。
运行程序,在页面点击新增(addUser)按钮,在日志中可以看到程序发生数据库错误,由于没有进行事务管理,查询数据库可以看到程序并没有因为第二次插入的错误而回滚第一次正常新增的数据,第一次的数据已放到DB的表中。
为保证数据的完整性和一致性,对于新增、修改、删除等DML数据操纵语言或连续操纵数据库的业务应进行事务管理,而Spring也提供了相应的机制,而Spring的事务控制,也是Spring AOP切面最直面的体现。以此程序为例,将Spring 声明性事务通过AOP切面放到需要事务控制的代码中。
打开 ApplincationContext.xml ,在命名空间声明中加入aop和事务命名:
在<beans>节点中加入事务声明:
- <tx:advice id="txAdvice" transaction-manager="transactionManage">
- <tx:attributes>
- <tx:method name="add*" propagation="REQUIRED"/>
- <tx:method name="del*" propagation="REQUIRED"/>
- <tx:method name="update*" propagation="REQUIRED"/>
- <tx:method name="*" read-only="true"/>
- </tx:attributes>
- </tx:advice>
声明意为:Spring创建了一个id为txAdvice的事务。在受到此事务管理的类中,凡方法名中含有<tx:attributes>中节点定义的name属性(add*,del*,update*),都会依据节点定义的propagation属性(REQUIRED),即事务的隔离级别进行事务控制。但Spring怎么知道哪些代码在事务控制范围之内?Spring是通过切面声明来达到的。
在<beans>中加入AOP声明:
- <aop:config>
- <aop:pointcut id="pointcutManage" expression="execution(* com.test.struts.service.*.*(..))"/>
- <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcutManage"/>
- </aop:config>
aop:pointcut 指将 expression 中给出的类声明成id为 pointcutManage 的切入点。
aop:advisor 指将id为 pointcutManage 的切入点带入到id为 txAdvice 的事务控制中。
配置完成后,删除表数据,再次将程序部署到服务器运行,发现业务层 UserService.java 捕获到DB主键冲突错误,查询数据库会发现没有新增记录,因为Spring已将UserService.java通过切面纳入到事务管理中,如发生错误,Spring会主动通过事务将事务回滚。
另外,Spring也可通过J2EE5.0注解来完成事务控制声明。