使用动态代理实现数据库事务

Posted kzd666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用动态代理实现数据库事务相关的知识,希望对你有一定的参考价值。

数据库sql:

技术分享图片
 1 create table T_USER
 2 (
 3    USER_ID              VARCHAR(10)            not null,
 4    USER_NAME            VARCHAR(30)            not null,
 5    PASSWORD             VARCHAR(20)            not null,
 6    CONTACT_TEL          VARCHAR(30),
 7    EMAIL                VARCHAR(30),
 8    CREATE_DATE          DATE,
 9    constraint P_KEY_1 primary key (USER_ID)
10 );
11 
12 insert into t_user(user_id, user_name, password) values(‘root‘, ‘系统管理员‘, ‘root‘);
技术分享图片
ConnectionManager.java(数据库连接管理)
技术分享图片
 1 package dynamicProxyTransaction;
 2 
 3 import java.sql.Connection;
 4 import java.sql.DriverManager;
 5 import java.sql.SQLException;
 6 
 7 public class ConnectionManager {
 8     private ConnectionManager() {
 9     }
10 
11     private static ThreadLocal<Connection> threadConn = new ThreadLocal<Connection>();
12 
13     // 获取数据库连接
14     public static Connection getConnection() {
15         Connection conn = threadConn.get();
16         if (conn == null) {
17             try {
18                 Class.forName("com.ibm.db2.jcc.DB2Driver");
19                 conn = DriverManager.getConnection(
20                         "jdbc:db2://127.0.0.1:50000/DRP", "db2admin", "619100");
21             } catch (ClassNotFoundException e) {
22                 e.printStackTrace();
23             } catch (SQLException e) {
24                 e.printStackTrace();
25             }
26             threadConn.set(conn);
27         }
28         return conn;
29     }
30 
31     // 设置事务手动提交
32     public static void benigTransction(Connection conn) {
33         try {
34             if (conn != null) {
35                 if (conn.getAutoCommit()) {
36                     conn.setAutoCommit(false);
37                 }
38             }
39         } catch (SQLException e) {
40             e.printStackTrace();
41         }
42     }
43 
44     // 提交事务
45     public static void endTransction(Connection conn) {
46         try {
47             if (conn != null) {
48                 if (!conn.getAutoCommit()) {
49                     conn.commit();
50                 }
51             }
52         } catch (SQLException e) {
53             e.printStackTrace();
54         }
55     }
56 
57     // 设置Connection的原始状态
58     public static void recoverTransction(Connection conn) {
59         try {
60             if (conn != null) {
61                 if (conn.getAutoCommit()) {
62                     conn.setAutoCommit(false);
63                 } else {
64                     conn.setAutoCommit(true);
65                 }
66             }
67         } catch (SQLException e) {
68             e.printStackTrace();
69         }
70     }
71 
72     // 发生异常回滚事务
73     public static void rollback(Connection conn) {
74         try {
75             if (conn != null) {
76                 conn.rollback();
77             }
78         } catch (SQLException e) {
79             e.printStackTrace();
80         }
81     }
82 
83     // 关闭连接,并将其从当前线程删除
84     public static void close() {
85         Connection conn = threadConn.get();
86         if (conn != null) {
87             try {
88                 conn.close();
89                 conn = null;
90                 threadConn.remove();
91             } catch (SQLException e) {
92                 e.printStackTrace();
93             }
94         }
95     }
96 }
技术分享图片

User.java(实体类)

技术分享图片
 1 package dynamicProxyTransaction;
 2 
 3 import java.util.Date;
 4 
 5 public class User {
 6     // 用户ID
 7         private String id;
 8         // 用户名称
 9         private String name;
10         // 登陆密码
11         private String password;
12         // 联系电话
13         private String contact_tel;
14         // 电子邮件
15         private String email;
16         // 用户创建日期
17         private Date create_date;
18 
19         public String getId() {
20             return id;
21         }
22 
23         public void setId(String id) {
24             this.id = id;
25         }
26 
27         public String getName() {
28             return name;
29         }
30 
31         public void setName(String name) {
32             this.name = name;
33         }
34 
35         public String getPassword() {
36             return password;
37         }
38 
39         public void setPassword(String password) {
40             this.password = password;
41         }
42 
43         public String getContact_tel() {
44             return contact_tel == null ? "" : contact_tel;
45         }
46 
47         public void setContact_tel(String contact_tel) {
48             this.contact_tel = contact_tel;
49         }
50 
51         public String getEmail() {
52             return email == null ? "" : email;
53         }
54 
55         public void setEmail(String email) {
56             this.email = email;
57         }
58 
59         public Date getCreate_date() {
60             return create_date;
61         }
62 
63         public void setCreate_date(Date create_date) {
64             this.create_date = create_date;
65         }
66 }
技术分享图片

UserDAO.java(用户相关的数据库操作)

技术分享图片
1 package dynamicProxyTransaction;
2 
3 import java.sql.SQLException;
4 
5 public interface UserDAO {
6     public User selUser(String id ) throws SQLException ;
7 }
技术分享图片

UserDAOImpl.java(UserDAO实现类)

技术分享图片
 1 package dynamicProxyTransaction;
 2 
 3 import java.sql.Connection;
 4 import java.sql.PreparedStatement;
 5 import java.sql.ResultSet;
 6 import java.sql.SQLException;
 7 
 8 public class UserDAOImpl implements UserDAO {
 9     @Override
10     public User selUser(String id) throws SQLException {
11         ResultSet resu = null;
12         String sql = "SELECT * FROM DB2ADMIN.T_USER WHERE USER_ID = ?";
13         Connection conn = ConnectionManager.getConnection();
14         PreparedStatement pstat = conn.prepareStatement(sql);
15         User user = null;
16         try {
17             pstat.setString(1, id);
18             resu = pstat.executeQuery();
19             if (resu.next()) {
20                 user = getUser(resu);
21             }
22         } finally {
23             if (resu != null) {
24                 resu.close();
25             }
26             if (pstat != null) {
27                 pstat.close();
28             }
29         }
30         return user;
31     }
32     // 获取用户
33         private User getUser(ResultSet resu) throws SQLException {
34             User user = new User();
35             user.setId(resu.getString("USER_ID"));
36             user.setName(resu.getString("USER_NAME"));
37             user.setPassword(resu.getString("PASSWORD"));
38             user.setContact_tel(resu.getString("CONTACT_TEL"));
39             user.setEmail(resu.getString("EMAIL"));
40             user.setCreate_date(resu.getTimestamp("CREATE_DATE"));
41             return user;
42         }
43 }
技术分享图片

UserManager.java(用户管理功能定义)

1 package dynamicProxyTransaction;
2 
3 public interface UserManager {
4     public User findUser(String id ) throws Exception ;
5 }

UserManagerImpl.java(UserManager实现类)

技术分享图片
 1 package dynamicProxyTransaction;
 2 
 3 import java.sql.SQLException;
 4 
 5 public class UserManagerImpl implements UserManager {
 6     // 这个和我以前写的不一样: 我都是写在每个方法中,写成属性应该好一点,减少创建对象的次数
 7     private UserDAO userDAO = null; 
 8 
 9     public UserManagerImpl() {
10         userDAO = new UserDAOImpl();
11     }
12 
13     public User findUser(String id) throws SQLException {
14         return userDAO.selUser(id);
15     }
16 }
技术分享图片

TransactionProxy.java(代理实现)

技术分享图片
 1 package dynamicProxyTransaction;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.InvocationTargetException;
 5 import java.lang.reflect.Method;
 6 import java.lang.reflect.Proxy;
 7 import java.sql.Connection;
 8 
 9 public class TransactionProxy implements InvocationHandler {
10     private Object obj = null;
11 
12     // obj:需要代理的类
13     public Object newProxyInstance(Object obj) {
14         this.obj = obj;
15         return Proxy.newProxyInstance(this.obj.getClass().getClassLoader(),
16                 this.obj.getClass().getInterfaces(), this);
17     }
18 
19     @Override
20     public Object invoke(Object proxy, Method method, Object[] args)
21             throws Throwable {
22         // 用于接收参数
23         Object param = null;
24         // 如果是以下方法开头,则代理事务
25         if (method.getName().startsWith("add")
26                 || method.getName().startsWith("modify")
27                 || method.getName().startsWith("find")
28                 || method.getName().startsWith("del")) {
29             Connection conn = ConnectionManager.getConnection();
30             try {
31                 // 手动提交事务
32                 ConnectionManager.benigTransction(conn);
33                 param = method.invoke(obj, args);
34                 // 提交事务
35                 ConnectionManager.endTransction(conn);
36             } catch (Exception e) {
37                 // 回滚事务
38                 ConnectionManager.rollback(conn);
39                 if (e instanceof InvocationTargetException) {
40                     InvocationTargetException inv = (InvocationTargetException) e;
41                     throw inv.getTargetException();
42                 } else {
43                     throw new Exception("操作失败!");
44                 }
45             } finally {
46                 // 还原状态
47                 ConnectionManager.recoverTransction(conn);
48                 ConnectionManager.close();
49             }
50         }
51         return param;
52     }
53 }
技术分享图片

Test.java(测试)

技术分享图片
 1 package dynamicProxyTransaction;
 2 
 3 public class Test {
 4     public static void main(String[] args) throws Exception {
 5         TransactionProxy transctionProxy = new TransactionProxy();
 6 
 7         // //产生代理对象
 8         UserManager userManager = (UserManager) transctionProxy
 9                 .newProxyInstance(new UserManagerImpl());
10         User user = userManager.findUser("root");
11         System.out.println("用户名:" + user.getName());
12     }
13     
14 }
技术分享图片

以上是关于使用动态代理实现数据库事务的主要内容,如果未能解决你的问题,请参考以下文章

分析动态代理给Spring事务埋下的坑

动态代理实现横切——封装事务

Spring声明式事务的实现方式选择(JDK动态代理与cglib)

分析动态代理给 Spring 事务埋下的坑

Java开发Spring之AOP详解(xml--注解->方法增强事务管理(声明事务的实现))

MyBatis框架—动态 SQL配置文件事务