参考文章:
    image.png

    1. package csdn;
    2. import java.io.PrintWriter;
    3. import java.lang.annotation.Documented;
    4. import java.lang.annotation.ElementType;
    5. import java.lang.annotation.Inherited;
    6. import java.lang.annotation.Retention;
    7. import java.lang.annotation.RetentionPolicy;
    8. import java.lang.annotation.Target;
    9. import java.lang.reflect.InvocationHandler;
    10. import java.lang.reflect.InvocationTargetException;
    11. import java.lang.reflect.Method;
    12. import java.lang.reflect.Proxy;
    13. import java.sql.Connection;
    14. import java.sql.DriverManager;
    15. import java.sql.PreparedStatement;
    16. import java.sql.SQLException;
    17. import java.sql.SQLFeatureNotSupportedException;
    18. import java.util.logging.Logger;
    19. import javax.sql.DataSource;
    20. /**
    21. * 手写事务管理器
    22. */
    23. public class TranscationalManager {
    24. /**
    25. * 开启事务
    26. */
    27. final static ThreadLocal<Boolean> transcational = new ThreadLocal<Boolean>();
    28. /**
    29. * 数据库连接
    30. */
    31. final static ThreadLocal<Connection> currentConnection = new ThreadLocal<Connection>();
    32. static DataSource dataSource=new DataSource() {
    33. @Override
    34. public <T> T unwrap(Class<T> iface) throws SQLException {
    35. // TODO Auto-generated method stub
    36. return null;
    37. }
    38. @Override
    39. public boolean isWrapperFor(Class<?> iface) throws SQLException {
    40. // TODO Auto-generated method stub
    41. return false;
    42. }
    43. @Override
    44. public void setLoginTimeout(int seconds) throws SQLException {
    45. // TODO Auto-generated method stub
    46. }
    47. @Override
    48. public void setLogWriter(PrintWriter out) throws SQLException {
    49. // TODO Auto-generated method stub
    50. }
    51. @Override
    52. public Logger getParentLogger() throws SQLFeatureNotSupportedException {
    53. // TODO Auto-generated method stub
    54. return null;
    55. }
    56. @Override
    57. public int getLoginTimeout() throws SQLException {
    58. // TODO Auto-generated method stub
    59. return 0;
    60. }
    61. @Override
    62. public PrintWriter getLogWriter() throws SQLException {
    63. // TODO Auto-generated method stub
    64. return null;
    65. }
    66. @Override
    67. public Connection getConnection(String username, String password) throws SQLException {
    68. // TODO Auto-generated method stub
    69. return null;
    70. }
    71. @Override
    72. public Connection getConnection() throws SQLException {
    73. Connection conn = null;
    74. String driverClass = "com.mysql.jdbc.Driver";
    75. String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8";
    76. String user = "root";
    77. String password = "denglintao";
    78. try {
    79. Class.forName(driverClass);
    80. } catch (ClassNotFoundException e) {
    81. // TODO Auto-generated catch block
    82. e.printStackTrace();
    83. }
    84. conn = DriverManager.getConnection(url, user, password);
    85. return conn;
    86. }
    87. };
    88. static class ConnectionProxy implements InvocationHandler {
    89. Connection targetConn;
    90. public Connection proxyConnection(Connection targetConn) {
    91. this.targetConn = targetConn;
    92. Connection proxyConn = (Connection) Proxy.newProxyInstance(targetConn.getClass().getClassLoader(),
    93. new Class[] { Connection.class }, this);
    94. return proxyConn;
    95. }
    96. @Override
    97. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    98. if (method.getName().equals("close")) {
    99. // 清除当前的数据库连接
    100. if (isOpenTranscational()) {
    101. // 若开启事务的 连接将不做操作
    102. return null;
    103. }
    104. targetConn.setAutoCommit(true);
    105. targetConn.close();
    106. return null;
    107. }
    108. Object result = method.invoke(targetConn, args);
    109. return result;
    110. }
    111. public Connection getTargetConn() {
    112. return targetConn;
    113. }
    114. }
    115. @Target({ ElementType.METHOD, ElementType.TYPE })
    116. @Retention(RetentionPolicy.RUNTIME)
    117. @Inherited
    118. @Documented
    119. public @interface Transactional {
    120. String value() default "";
    121. }
    122. static class TranscationalInvocationHandler implements InvocationHandler {
    123. public static Object proxyTranscational(Object service) throws InstantiationException, IllegalAccessException {
    124. // 此处若有 @Transactional 代理
    125. Class<? extends Object> clazz = service.getClass();
    126. Class<?>[] interfaces = clazz.getInterfaces();
    127. boolean isProxy = false;
    128. for (Method method : clazz.getDeclaredMethods()) {
    129. if (method.isAnnotationPresent(Transactional.class)) {
    130. isProxy = true;
    131. break;
    132. }
    133. }
    134. if (isProxy) {
    135. return Proxy.newProxyInstance(clazz.getClassLoader(), interfaces,
    136. new TranscationalInvocationHandler(service));
    137. } else {
    138. return service;
    139. }
    140. }
    141. Object traget;
    142. public TranscationalInvocationHandler(Object bean) {
    143. this.traget = bean;
    144. }
    145. public Object getTraget() {
    146. return traget;
    147. }
    148. @Override
    149. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    150. Object invoke = null;
    151. Method declaredMethod = traget.getClass().getDeclaredMethod(method.getName(), method.getParameterTypes());
    152. // 不需要事务
    153. if (!declaredMethod.isAnnotationPresent(Transactional.class)) {
    154. try {
    155. return method.invoke(traget, args);
    156. } catch (InvocationTargetException e) {
    157. throw e.getTargetException();
    158. } finally {
    159. // 原本不存在事务时候 才释放资源
    160. if (!TranscationalManager.isOpenTranscational()) {
    161. TranscationalManager.closeConnection();// 防止开发者在dao层面拿取数据库连接 没有关闭导致连接泄漏
    162. TranscationalManager.release();
    163. }
    164. }
    165. }
    166. // 如果原本存在事务,那么加入事务
    167. if (TranscationalManager.isOpenTranscational()) {
    168. try {
    169. // 数据库连接处理
    170. return invoke = method.invoke(traget, args);
    171. } catch (InvocationTargetException e) {
    172. TranscationalManager.rollback();
    173. throw e.getTargetException();
    174. }
    175. }
    176. // 需要开启事务
    177. try {
    178. // 有事务注解的开启事务
    179. TranscationalManager.openTranscational();
    180. // 数据库连接处理
    181. invoke = method.invoke(traget, args);
    182. TranscationalManager.commit();
    183. } catch (InvocationTargetException e) {
    184. TranscationalManager.rollback();
    185. throw e.getTargetException();
    186. } finally {
    187. // 关闭连接 释放资源
    188. TranscationalManager.closeConnection();
    189. TranscationalManager.release();
    190. }
    191. return invoke;
    192. }
    193. }
    194. /**
    195. * 代理service层的事务控制
    196. */
    197. @SuppressWarnings("unchecked")
    198. public static <T> T proxyTranscationalService(T serviceBean) {
    199. try {
    200. return (T) TranscationalInvocationHandler.proxyTranscational(serviceBean);
    201. } catch (Exception e) {
    202. throw new RuntimeException(e);
    203. }
    204. }
    205. /**
    206. * 测试接口类
    207. * @Description:</p>
    208. * @author 邓霖涛
    209. * @date 2020年12月23日
    210. */
    211. public interface UserService{
    212. void modifyUsers() throws Exception;
    213. }
    214. public static class UserServiceImpl implements UserService{
    215. /**
    216. * 加上事务注解
    217. */
    218. @Transactional
    219. @Override
    220. public void modifyUsers() throws Exception {
    221. //操作1与操作2 同属于一个事务,
    222. //模拟dao操作1
    223. Connection conn = TranscationalManager.getConnection();
    224. PreparedStatement pst = conn.prepareStatement(" insert into user(user_name,password) values('姓名1','123' ) ");
    225. pst.executeUpdate();
    226. pst.close();
    227. conn.close();
    228. if(true) {
    229. // throw new RuntimeException("强制异常,让后面的执行不了,会发现前者并没有插入到数据库库中");
    230. }
    231. //模拟dao操作2
    232. Connection conn1 = getConnection();
    233. PreparedStatement pst1 = conn1.prepareStatement(" insert into user(user_name,password) values('姓名2','123' ) ");
    234. pst1.executeUpdate();
    235. pst1.close();
    236. conn1.close();
    237. if(true) {
    238. throw new RuntimeException("强制异常,让后面的执行不了,会发现前者并没有插入到数据库库中");
    239. }
    240. }
    241. }
    242. /**
    243. * 主函数测试
    244. */
    245. public static void main(String[] args) {
    246. //原本的service层的
    247. UserService userService = new UserServiceImpl();
    248. //事务管理代理
    249. userService = proxyTranscationalService(userService);
    250. try {
    251. //执行更新
    252. userService.modifyUsers();
    253. } catch (Exception e) {
    254. e.printStackTrace();
    255. }
    256. }
    257. /**
    258. * 获取数据库连接
    259. */
    260. public static Connection getConnection() throws SQLException {
    261. if (currentConnection.get() != null) {
    262. return currentConnection.get();
    263. }
    264. Connection conn = dataSource.getConnection();
    265. ConnectionProxy connectionProxy = new ConnectionProxy();
    266. Connection proxyConnection = connectionProxy.proxyConnection(conn);
    267. currentConnection.set(proxyConnection);
    268. if(TranscationalManager.isOpenTranscational()){
    269. conn.setAutoCommit(false);
    270. }else{
    271. conn.setAutoCommit(true);
    272. }
    273. return proxyConnection;
    274. }
    275. /**
    276. * 事务开启
    277. */
    278. static void openTranscational() {
    279. transcational.set(true);
    280. }
    281. /**
    282. * 是否开启事务 true开启/false未开启
    283. */
    284. static boolean isOpenTranscational() {
    285. boolean result = false;
    286. if (transcational.get() == null) {
    287. result = false;
    288. } else {
    289. result = transcational.get();
    290. }
    291. return result;
    292. }
    293. /**
    294. * 事务关闭
    295. */
    296. static void closeTranscational() {
    297. transcational.set(false);
    298. }
    299. /**
    300. * 事务提交
    301. */
    302. static void commit() throws SQLException {
    303. Connection conn = currentConnection.get();
    304. if (conn != null) {
    305. conn.commit();
    306. }
    307. }
    308. /**
    309. * 回滚
    310. */
    311. static void rollback() throws SQLException {
    312. Connection conn = currentConnection.get();
    313. if (conn != null) {
    314. conn.rollback();
    315. }
    316. }
    317. /**
    318. * 关闭连接,需要先关闭事务在调用此方法
    319. */
    320. static void closeConnection() throws SQLException {
    321. closeTranscational();
    322. Connection conn = currentConnection.get();
    323. if (conn != null) {
    324. conn.close();
    325. }
    326. }
    327. /**
    328. * 释放资源
    329. */
    330. static void release() {
    331. transcational.remove();
    332. currentConnection.remove();
    333. }
    334. }