zoukankan      html  css  js  c++  java
  • 面向切面编程开发事务

    一.面向切面编程开发事务
      为了解决重复的代码,提出了面向切面编程开发的概念,
      所谓的面向切面的开发就是针对指定的方法,可以在该方法执行之前或者之后织入一些辅助性得到代码

    1.开发出一个事务的注解

    1 //指定注解的使用范围 (只能在方法上使用)
    2 @Target(ElementType.METHOD)
    3 //定义注解的声明周期 (运行时有效)
    4 @Retention(RetentionPolicy.RUNTIME)
    5 public @interface Transactional {
    6 }

    2.调整业务层实现类 : 加上自己开发的注解
      如果有 "@Transactional" 则进行事务处理,否则就不处理

     1 public class EmpServiceImpl implements IEmpService {
     2     //需要调用数据层的方法所以需要确定数据层的实现类对象
     3     private IEmpDAO empDAO = new EmpDAOImpl();
     4     
     5     @Override
     6     @Transactional
     7     public boolean addEmp(Emp vo) throws Exception {
     8             return this.empDAO.insert(vo)>0;
     9     }
    10     @Override
    11     @Transactional
    12     public boolean removeEmpById(Integer id)  throws Exception {
    13             return this.empDAO.deleteById(id)>0;
    14     }
    15     @Override
    16     @Transactional
    17     public boolean editEmp(Emp vo) throws Exception  {
    18             return this.empDAO.update(vo)>0;
    19     }
    20     @Override
    21     @Transactional
    22     public Emp findEmpById(Integer id) throws Exception  {
    23             return this.empDAO.selectById(id);
    24     }
    25     @Override
    26     @Transactional
    27     public Map<String, Object> findAllSplit(String kw, Integer cp, Integer ls) throws Exception  {
    28         Map<String,Object> map = new HashMap<String, Object>();
    29             map.put("emplist",this.empDAO.selectSplitAll("%"+kw+"%", cp, ls));
    30             //统计数据量
    31             int number = this.empDAO.selectCount(kw);
    32             //计算出总的页数
    33             //int allPages = number/ls+number%ls==0?0:1;
    34             //int allPages = (int)Math.ceil(number/(double)ls));
    35             map.put("count",number);
    36             map.put("allPages",(int)Math.ceil(number/(double)ls));
    37             map.put("kw",kw);
    38             map.put("cp",cp);
    39             map.put("ls",ls);
    40             return map;
    41     }
    42     @Override
    43     @Transactional
    44     public boolean removeBacth(List<Object> ids) throws Exception  {
    45             return this.empDAO.deleteBatch(ids)>0;
    46     }
    47 }

    3.定义动态代理类

     1 public class ServiceProxy implements InvocationHandler {
     2     private Object obj; // 真实主题类对象
     3     private Connection conn;
     4 
     5     public ServiceProxy() {
     6     }
     7     public ServiceProxy(Object obj) {
     8         this.obj = obj;
     9     }
    10     @Override
    11     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    12         // 保存方法的返回值
    13         Object result = null;
    14         // 取得业务层实现类对象 (被代理的对象) 正在被执行的方法
    15         Method m = this.obj.getClass().getMethod(method.getName(), method.getParameterTypes());
    16         // 读取正在执行的方法上的注解
    17         Transactional transactional = m.getDeclaredAnnotation(Transactional.class);
    18         System.out.println("注解信息是: " + transactional);
    19         // 取得连接
    20         if (conn == null) 
    21             conn = DBUitl.getConnection();
    22             System.out.println("取得连接: " + conn);
    23             // 取得真实主体类对象 (就是业务层的实现类对象) 的反射对象
    24             Class<?> cls = this.obj.getClass();
    25         
    26         if (transactional == null) {
    27             System.out.println("没有事务处理");
    28             // 取得真实主题类对象中的所有属性 (业务层实现类对象中的 dao 层的实现类对象)
    29             for (Field fdao : cls.getDeclaredFields()) {
    30                 // 取消属性的封装
    31                 fdao.setAccessible(true);
    32                 // 取得属性的值
    33                 Object daoObj = fdao.get(this.obj);
    34                 // 取得业务层实现类中的 dao 层实现类的 conn 属性 (目的是为了其赋值)
    35                 Field fconn = daoObj.getClass().getDeclaredField("conn");
    36                 fconn.setAccessible(true);
    37                 // 为业务层实现类中的 dao层的实现类对象的 conn 赋值
    38                 fconn.set(daoObj, conn);
    39             }
    40             // 执行方法
    41             result = method.invoke(this.obj, args);
    42             // 关闭连接
    43             DBUitl.close(conn);
    44         } else {
    45             System.out.println("有事务处理");
    46             try {
    47                 // 取消事务的自动提交
    48                 conn.setAutoCommit(false);
    49                 // 取得真实主题类中的所有属性
    50                 for (Field fdaoimpl : cls.getDeclaredFields()) {
    51                     // 取消属性的封装
    52                     fdaoimpl.setAccessible(true);
    53                     // 取得属性的值
    54                     Object fdao = fdaoimpl.get(this.obj);
    55                     // 取得业务层实现类中的 dao 层 实现类的 conn 属性
    56                     Field fconn = fdao.getClass().getDeclaredField("conn");
    57                     fconn.setAccessible(true);
    58                     // 为业务层实现类中的 dao 层实现类的 conn 属性赋值
    59                     fconn.set(fdao, conn);
    60                 }
    61                 // 执行方法
    62                 result = method.invoke(this.obj, args);
    63                 // 提交事务
    64                 conn.commit();
    65             } catch (Exception e) {
    66                 conn.rollback();
    67                 e.printStackTrace();
    68             } finally {
    69                 DBUitl.close(conn);
    70             }
    71         }
    72         System.out.println("关闭连接" + conn);
    73         return result;
    74     }
    75 }

    4.定义出工厂类

     1 public class ServiceFactory {
     2     public static Object geiInstance(Class<?> cls) {
     3         try {
     4             //真实主体类对象
     5             Object obj = cls.newInstance();
     6             //取得代理类对象 
     7             InvocationHandler hander = new ServiceProxy(obj);
     8             //取得被代理之后的真实主题类对象
     9             Object proxyServiceObj = Proxy.newProxyInstance(hander.getClass().getClassLoader(), obj.getClass().getInterfaces(), hander);
    10             return proxyServiceObj;
    11         } catch (Exception e) {
    12             e.printStackTrace();
    13         }
    14         return null;
    15     }
    16 }

    5.测试

    1 public class Test {
    2     public static void main(String[] args) throws Exception {
    3         //取得真实主题对象
    4         IEmpService empService = (IEmpService)ServiceFactory.geiInstance(EmpServiceImpl.class);
    5         System.out.println(empService.findAllSplit("A", 1, 10));
    6     }
    7 }
  • 相关阅读:
    读书笔记-《编写可读代码的艺术》一
    maven报错Error:(4, 35) java:程序包org.springframework.context不存在
    AutoCAD.Net/C#.Net QQ群:193522571 当需要把wipeout加入到block中时,必须把wipeout放在objectidcollection中的第一位
    AutoCAD.Net/C#.Net QQ群:193522571 绘制椭圆及椭圆弧
    AutoCAD.Net/C#.Net QQ群:193522571 Nested Select后,如果有上一级图元则ResultNestedContainer不为Null,从小到大,从父亲到爷爷
    AutoCAD.Net/C#.Net QQ群:193522571 标注对象Dimension中的DimensionText和Measurement的区别
    AutoCAD.Net/C#.Net QQ群:193522571 同一套窗体代码,同时用在Winform、PvBox和PvTools中
    AutoCAD.Net/C#.Net QQ群:193522571 当用户使用的不是默认的WCS坐标系时,打印程序容易打成空白,因为点没有转换
    AutoCAD.Net/C#.Net QQ群:193522571 ComBobox绑定Datatable并去除重复!
    AutoCAD.Net/C#.Net QQ群:193522571 字段包含于一个字符串的SQL
  • 原文地址:https://www.cnblogs.com/yslf/p/10732147.html
Copyright © 2011-2022 走看看