From da85487dad4f1943fa2879f8c0d2a5aafe90603c Mon Sep 17 00:00:00 2001 From: ZhangZiSheng001 <18826241741@163.com> Date: Thu, 2 Apr 2020 00:04:31 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=A0=BC=E5=BC=8F=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 472 +++++++++--------- pom.xml | 123 +++-- src/main/java/cn/zzs/dbcp/JDBCUtils.java | 190 +++---- .../java/cn/zzs/dbcp/BasicDataSourceTest.java | 238 ++++----- .../zzs/dbcp/BasicManagedDataSourceTest.java | 159 +++--- 5 files changed, 584 insertions(+), 598 deletions(-) diff --git a/README.md b/README.md index 093f5c6..07660fa 100644 --- a/README.md +++ b/README.md @@ -104,22 +104,22 @@ ```xml - junit - junit - 4.12 - test + junit + junit + 4.12 + test - org.apache.commons - commons-dbcp2 - 2.6.0 + org.apache.commons + commons-dbcp2 + 2.6.0 - log4j - log4j - 1.2.17 + log4j + log4j + 1.2.17 @@ -170,14 +170,14 @@ maxWaitMillis=-1 路径:`cn.zzs.dbcp` ```java - // 导入配置文件 - Properties properties = new Properties(); - InputStream in = JDBCUtil.class.getClassLoader().getResourceAsStream("dbcp.properties"); - properties.load(in); - // 根据配置文件内容获得数据源对象 - DataSource dataSource = BasicDataSourceFactory.createDataSource(properties); - // 获得连接 - Connection conn = dataSource.getConnection(); + // 导入配置文件 + Properties properties = new Properties(); + InputStream in = JDBCUtil.class.getClassLoader().getResourceAsStream("dbcp.properties"); + properties.load(in); + // 根据配置文件内容获得数据源对象 + DataSource dataSource = BasicDataSourceFactory.createDataSource(properties); + // 获得连接 + Connection conn = dataSource.getConnection(); ``` ## 编写测试类 @@ -185,34 +185,34 @@ maxWaitMillis=-1 这里以保存用户为例,路径test目录下的`cn.zzs.dbcp`。 ```java - @Test - public void save() throws SQLException { - // 创建sql - String sql = "insert into demo_user values(null,?,?,?,?,?)"; - Connection connection = null; - PreparedStatement statement = null; - try { - // 获得连接 - connection = JDBCUtils.getConnection(); - // 开启事务设置非自动提交 - connection.setAutoCommit(false); - // 获得Statement对象 - statement = connection.prepareStatement(sql); - // 设置参数 - statement.setString(1, "zzf003"); - statement.setInt(2, 18); - statement.setDate(3, new Date(System.currentTimeMillis())); - statement.setDate(4, new Date(System.currentTimeMillis())); - statement.setBoolean(5, false); - // 执行 - statement.executeUpdate(); - // 提交事务 - connection.commit(); - } finally { - // 释放资源 - JDBCUtils.release(connection, statement, null); - } - } + @Test + public void save() throws SQLException { + // 创建sql + String sql = "insert into demo_user values(null,?,?,?,?,?)"; + Connection connection = null; + PreparedStatement statement = null; + try { + // 获得连接 + connection = JDBCUtils.getConnection(); + // 开启事务设置非自动提交 + connection.setAutoCommit(false); + // 获得Statement对象 + statement = connection.prepareStatement(sql); + // 设置参数 + statement.setString(1, "zzf003"); + statement.setInt(2, 18); + statement.setDate(3, new Date(System.currentTimeMillis())); + statement.setDate(4, new Date(System.currentTimeMillis())); + statement.setBoolean(5, false); + // 执行 + statement.executeUpdate(); + // 提交事务 + connection.commit(); + } finally { + // 释放资源 + JDBCUtils.release(connection, statement, null); + } + } ``` @@ -501,51 +501,51 @@ accessToUnderlyingConnectionAllowed=false 5. 开启空闲资源回收线程(如果设置`timeBetweenEvictionRunsMillis`为正数)。 ```java - protected DataSource createDataSource() throws SQLException { - if(closed) { - throw new SQLException("Data source is closed"); - } - if(dataSource != null) { - return dataSource; - } - - synchronized(this) { - if(dataSource != null) { - return dataSource; - } - // 注册MBean,用于支持JMX,这方面的内容不在这里扩展 - jmxRegister(); - - // 创建原生Connection工厂:本质就是持有数据库驱动对象和几个连接参数 - final ConnectionFactory driverConnectionFactory = createConnectionFactory(); - - // 将driverConnectionFactory包装成池化Connection工厂 - PoolableConnectionFactory poolableConnectionFactory = createPoolableConnectionFactory(driverConnectionFactory); - // 设置PreparedStatements缓存(其实在这里可以发现,上面创建池化工厂时就设置了缓存,这里没必要再设置一遍) - poolableConnectionFactory.setPoolStatements(poolPreparedStatements); - poolableConnectionFactory.setMaxOpenPreparedStatements(maxOpenPreparedStatements); - - // 创建数据库连接池对象GenericObjectPool,用于管理连接 - // BasicDataSource将持有GenericObjectPool对象 - createConnectionPool(poolableConnectionFactory); - - // 创建PoolingDataSource对象 - // 该对象持有GenericObjectPool对象的引用 - DataSource newDataSource = createDataSourceInstance(); - newDataSource.setLogWriter(logWriter); - - // 根据我们设置的initialSize创建初始连接 - for(int i = 0; i < initialSize; i++) { - connectionPool.addObject(); - } - - // 开启连接池的evictor线程 - startPoolMaintenance(); - // 最后BasicDataSource将持有上面创建的PoolingDataSource对象 - dataSource = newDataSource; - return dataSource; - } - } + protected DataSource createDataSource() throws SQLException { + if(closed) { + throw new SQLException("Data source is closed"); + } + if(dataSource != null) { + return dataSource; + } + + synchronized(this) { + if(dataSource != null) { + return dataSource; + } + // 注册MBean,用于支持JMX,这方面的内容不在这里扩展 + jmxRegister(); + + // 创建原生Connection工厂:本质就是持有数据库驱动对象和几个连接参数 + final ConnectionFactory driverConnectionFactory = createConnectionFactory(); + + // 将driverConnectionFactory包装成池化Connection工厂 + PoolableConnectionFactory poolableConnectionFactory = createPoolableConnectionFactory(driverConnectionFactory); + // 设置PreparedStatements缓存(其实在这里可以发现,上面创建池化工厂时就设置了缓存,这里没必要再设置一遍) + poolableConnectionFactory.setPoolStatements(poolPreparedStatements); + poolableConnectionFactory.setMaxOpenPreparedStatements(maxOpenPreparedStatements); + + // 创建数据库连接池对象GenericObjectPool,用于管理连接 + // BasicDataSource将持有GenericObjectPool对象 + createConnectionPool(poolableConnectionFactory); + + // 创建PoolingDataSource对象 + // 该对象持有GenericObjectPool对象的引用 + DataSource newDataSource = createDataSourceInstance(); + newDataSource.setLogWriter(logWriter); + + // 根据我们设置的initialSize创建初始连接 + for(int i = 0; i < initialSize; i++) { + connectionPool.addObject(); + } + + // 开启连接池的evictor线程 + startPoolMaintenance(); + // 最后BasicDataSource将持有上面创建的PoolingDataSource对象 + dataSource = newDataSource; + return dataSource; + } + } ``` 以上方法涉及到几个类,这里再补充下`UML`图。 @@ -1154,24 +1154,24 @@ accessToUnderlyingConnectionAllowed=false 本文在前面例子的基础上增加以下依赖,因为是web项目,所以打包方式为`war`: ```xml - - javax.servlet - jstl - 1.2 - provided - - - javax.servlet - javax.servlet-api - 3.1.0 - provided - - - javax.servlet.jsp - javax.servlet.jsp-api - 2.2.1 - provided - + + javax.servlet + jstl + 1.2 + provided + + + javax.servlet + javax.servlet-api + 3.1.0 + provided + + + javax.servlet.jsp + javax.servlet.jsp-api + 2.2.1 + provided + ``` ## 编写context.xml @@ -1181,20 +1181,20 @@ accessToUnderlyingConnectionAllowed=false ```xml - + + /> + /> ``` @@ -1233,17 +1233,17 @@ accessToUnderlyingConnectionAllowed=false Test DriverAdapterCPDS bean/DriverAdapterCPDS org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS - - - Test SharedPoolDataSource - bean/SharedPoolDataSourceFactory - org.apache.commons.dbcp2.datasources.SharedPoolDataSource - + + + Test SharedPoolDataSource + bean/SharedPoolDataSourceFactory + org.apache.commons.dbcp2.datasources.SharedPoolDataSource + Test erUserPoolDataSource bean/erUserPoolDataSourceFactory org.apache.commons.dbcp2.datasources.erUserPoolDataSource - + ``` ## 编写jsp @@ -1254,22 +1254,22 @@ accessToUnderlyingConnectionAllowed=false <% // 获得名称服务的上下文对象 - Context initCtx = new InitialContext(); - Context envCtx = (Context)initCtx.lookup("java:comp/env/"); - - // 查找指定名字的对象 - DataSource ds = (DataSource)envCtx.lookup("bean/SharedPoolDataSourceFactory"); - - DataSource ds2 = (DataSource)envCtx.lookup("bean/PerUserPoolDataSourceFactory"); - // 获取连接 - Connection conn = ds.getConnection("root","root"); - System.out.println("conn" + conn); + Context initCtx = new InitialContext(); + Context envCtx = (Context)initCtx.lookup("java:comp/env/"); + + // 查找指定名字的对象 + DataSource ds = (DataSource)envCtx.lookup("bean/SharedPoolDataSourceFactory"); + + DataSource ds2 = (DataSource)envCtx.lookup("bean/PerUserPoolDataSourceFactory"); + // 获取连接 + Connection conn = ds.getConnection("root","root"); + System.out.println("conn" + conn); Connection conn2 = ds2.getConnection("zzf","zzf"); System.out.println("conn2" + conn2); // ... 使用连接操作数据库,以及释放资源 ... - conn.close(); - conn2.close(); + conn.close(); + conn2.close(); %> ``` @@ -1325,12 +1325,12 @@ XA RECOVER; -- 查看处于prepare状态的事务列表 ```xml - - javax.transaction - jta - 1.1 - - + + javax.transaction + jta + 1.1 + + com.atomikos transactions-jdbc 3.9.3 @@ -1342,42 +1342,42 @@ XA RECOVER; -- 查看处于prepare状态的事务列表 这里千万记得要设置`DefaultCatalog`,否则当前事务中注册不同资源管理器时,可能都会被当成同一个资源管理器而拒绝注册并报错,因为这个问题,花了我好长时间才解决。 ```java - public BasicManagedDataSource getBasicManagedDataSource( - TransactionManager transactionManager, - String url, - String username, - String password) { - BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource(); - basicManagedDataSource.setTransactionManager(transactionManager); - basicManagedDataSource.setUrl(url); - basicManagedDataSource.setUsername(username); - basicManagedDataSource.setPassword(password); - basicManagedDataSource.setDefaultAutoCommit(false); - basicManagedDataSource.setXADataSource("com.mysql.cj.jdbc.MysqlXADataSource"); - return basicManagedDataSource; - } - @Test - public void test01() throws Exception { - // 获得事务管理器 - TransactionManager transactionManager = new UserTransactionManager(); - - // 获取第一个数据库的数据源 - BasicManagedDataSource basicManagedDataSource1 = getBasicManagedDataSource( - transactionManager, - "jdbc:mysql://localhost:3306/github_demo?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=true", - "root", - "root"); - // 注意,这一步非常重要 - basicManagedDataSource1.setDefaultCatalog("github_demo"); - - // 获取第二个数据库的数据源 - BasicManagedDataSource basicManagedDataSource2 = getBasicManagedDataSource( - transactionManager, - "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=true", - "zzf", - "zzf"); - // 注意,这一步非常重要 - basicManagedDataSource1.setDefaultCatalog("test"); + public BasicManagedDataSource getBasicManagedDataSource( + TransactionManager transactionManager, + String url, + String username, + String password) { + BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource(); + basicManagedDataSource.setTransactionManager(transactionManager); + basicManagedDataSource.setUrl(url); + basicManagedDataSource.setUsername(username); + basicManagedDataSource.setPassword(password); + basicManagedDataSource.setDefaultAutoCommit(false); + basicManagedDataSource.setXADataSource("com.mysql.cj.jdbc.MysqlXADataSource"); + return basicManagedDataSource; + } + @Test + public void test01() throws Exception { + // 获得事务管理器 + TransactionManager transactionManager = new UserTransactionManager(); + + // 获取第一个数据库的数据源 + BasicManagedDataSource basicManagedDataSource1 = getBasicManagedDataSource( + transactionManager, + "jdbc:mysql://localhost:3306/github_demo?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=true", + "root", + "root"); + // 注意,这一步非常重要 + basicManagedDataSource1.setDefaultCatalog("github_demo"); + + // 获取第二个数据库的数据源 + BasicManagedDataSource basicManagedDataSource2 = getBasicManagedDataSource( + transactionManager, + "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=true", + "zzf", + "zzf"); + // 注意,这一步非常重要 + basicManagedDataSource1.setDefaultCatalog("test"); } ``` @@ -1386,56 +1386,56 @@ XA RECOVER; -- 查看处于prepare状态的事务列表 通过运行代码可以发现,当数据库1和2的操作都成功,才会提交,只要其中一个数据库执行失败,两个操作都会回滚。 ```java - @Test - public void test01() throws Exception { - Connection connection1 = null; - Statement statement1 = null; - Connection connection2 = null; - Statement statement2 = null; - transactionManager.begin(); - try { - // 获取连接并进行数据库操作,这里会将会将XAResource注册到当前线程的XA事务对象 - /** - * XA START xid1;-- 启动一个事务,并使之为active状态 - */ - connection1 = basicManagedDataSource1.getConnection(); - statement1 = connection1.createStatement(); - /** - * update github_demo.demo_user set deleted = 1 where id = '1'; -- 事务中的语句 - */ - boolean result1 = statement1.execute("update github_demo.demo_user set deleted = 1 where id = '1'"); - System.out.println(result1); - - /** - * XA START xid2;-- 启动一个事务,并使之为active状态 - */ - connection2 = basicManagedDataSource2.getConnection(); - statement2 = connection2.createStatement(); - /** - * update test.demo_user set deleted = 1 where id = '1'; -- 事务中的语句 - */ - boolean result2 = statement2.execute("update test.demo_user set deleted = 1 where id = '1'"); - System.out.println(result2); - - /** - * 当这执行以下语句: - * XA END xid1; -- 把事务置为idle状态 - * XA PREPARE xid1; -- 把事务置为prepare状态 - * XA END xid2; -- 把事务置为idle状态 - * XA PREPARE xid2; -- 把事务置为prepare状态 - * XA COMMIT xid1; -- 提交事务 - * XA COMMIT xid2; -- 提交事务 - */ - transactionManager.commit(); - } catch(Exception e) { - e.printStackTrace(); - } finally { - statement1.close(); - statement2.close(); - connection1.close(); - connection2.close(); - } - } + @Test + public void test01() throws Exception { + Connection connection1 = null; + Statement statement1 = null; + Connection connection2 = null; + Statement statement2 = null; + transactionManager.begin(); + try { + // 获取连接并进行数据库操作,这里会将会将XAResource注册到当前线程的XA事务对象 + /** + * XA START xid1;-- 启动一个事务,并使之为active状态 + */ + connection1 = basicManagedDataSource1.getConnection(); + statement1 = connection1.createStatement(); + /** + * update github_demo.demo_user set deleted = 1 where id = '1'; -- 事务中的语句 + */ + boolean result1 = statement1.execute("update github_demo.demo_user set deleted = 1 where id = '1'"); + System.out.println(result1); + + /** + * XA START xid2;-- 启动一个事务,并使之为active状态 + */ + connection2 = basicManagedDataSource2.getConnection(); + statement2 = connection2.createStatement(); + /** + * update test.demo_user set deleted = 1 where id = '1'; -- 事务中的语句 + */ + boolean result2 = statement2.execute("update test.demo_user set deleted = 1 where id = '1'"); + System.out.println(result2); + + /** + * 当这执行以下语句: + * XA END xid1; -- 把事务置为idle状态 + * XA PREPARE xid1; -- 把事务置为prepare状态 + * XA END xid2; -- 把事务置为idle状态 + * XA PREPARE xid2; -- 把事务置为prepare状态 + * XA COMMIT xid1; -- 提交事务 + * XA COMMIT xid2; -- 提交事务 + */ + transactionManager.commit(); + } catch(Exception e) { + e.printStackTrace(); + } finally { + statement1.close(); + statement2.close(); + connection1.close(); + connection2.close(); + } + } ``` > 相关源码请移步:https://github.com/ZhangZiSheng001/dbcp-demo diff --git a/pom.xml b/pom.xml index 24c031c..2e3ad0c 100644 --- a/pom.xml +++ b/pom.xml @@ -1,68 +1,67 @@ - - 4.0.0 - cn.zzs - DBCP-demo - war - 1.0.0 - DBCP-demo - http://maven.apache.org - - - - junit - junit - 4.12 - test - - - - org.apache.commons - commons-dbcp2 - 2.6.0 - - - - log4j - log4j - 1.2.17 - - - - mysql - mysql-connector-java - 8.0.15 - - - - javax.servlet - jstl - 1.2 - provided - - - javax.servlet - javax.servlet-api - 3.1.0 - provided - - - javax.servlet.jsp - javax.servlet.jsp-api - 2.2.1 - provided - + + 4.0.0 + cn.zzs + DBCP-demo + war + 1.0.0 + DBCP-demo + http://maven.apache.org + + + + junit + junit + 4.12 + test + + + + org.apache.commons + commons-dbcp2 + 2.6.0 + + + + log4j + log4j + 1.2.17 + + + + mysql + mysql-connector-java + 8.0.15 + + + + javax.servlet + jstl + 1.2 + provided + + + javax.servlet + javax.servlet-api + 3.1.0 + provided + + + javax.servlet.jsp + javax.servlet.jsp-api + 2.2.1 + provided + - - javax.transaction - jta - 1.1 - - + + javax.transaction + jta + 1.1 + + com.atomikos transactions-jdbc 3.9.3 - + diff --git a/src/main/java/cn/zzs/dbcp/JDBCUtils.java b/src/main/java/cn/zzs/dbcp/JDBCUtils.java index bfe1ae2..ca87898 100644 --- a/src/main/java/cn/zzs/dbcp/JDBCUtils.java +++ b/src/main/java/cn/zzs/dbcp/JDBCUtils.java @@ -20,107 +20,107 @@ import org.apache.commons.logging.LogFactory; */ public class JDBCUtils { - private static DataSource dataSource; + private static DataSource dataSource; - private static ThreadLocal tl = new ThreadLocal<>(); + private static ThreadLocal tl = new ThreadLocal<>(); - private static final Object obj = new Object(); + private static final Object obj = new Object(); - private static final Log log = LogFactory.getLog(JDBCUtils.class); + private static final Log log = LogFactory.getLog(JDBCUtils.class); - static { - init(); - } + static { + init(); + } - /** - * - *

获取数据库连接对象的方法,线程安全

- * @author: zzs - * @date: 2019年8月31日 下午9:22:29 - * @return: Connection - */ - public static Connection getConnection() throws SQLException { - // 从当前线程中获取连接对象 - Connection connection = tl.get(); - // 判断为空的话,创建连接并绑定到当前线程 - if(connection == null) { - synchronized(obj) { - if((connection = tl.get()) == null) { - connection = createConnection(); - tl.set(connection); - } - } - } - return connection; - } + /** + * + *

获取数据库连接对象的方法,线程安全

+ * @author: zzs + * @date: 2019年8月31日 下午9:22:29 + * @return: Connection + */ + public static Connection getConnection() throws SQLException { + // 从当前线程中获取连接对象 + Connection connection = tl.get(); + // 判断为空的话,创建连接并绑定到当前线程 + if(connection == null) { + synchronized(obj) { + if((connection = tl.get()) == null) { + connection = createConnection(); + tl.set(connection); + } + } + } + return connection; + } - /** - * - *

释放资源

- * @author: zzs - * @date: 2019年8月31日 下午9:39:24 - * @param conn - * @param statement - * @return: void - */ - public static void release(Connection conn, Statement statement, ResultSet resultSet) { - if(resultSet != null) { - try { - resultSet.close(); - } catch(SQLException e) { - log.error("关闭ResultSet对象异常", e); - } - } - if(statement != null) { - try { - statement.close(); - } catch(SQLException e) { - log.error("关闭Statement对象异常", e); - } - } - // 注意:这里不关闭连接 - if(conn != null) { - try { - conn.close(); - tl.remove(); - } catch(SQLException e) { - log.error("关闭Connection对象异常", e); - } - } - } + /** + * + *

释放资源

+ * @author: zzs + * @date: 2019年8月31日 下午9:39:24 + * @param conn + * @param statement + * @return: void + */ + public static void release(Connection conn, Statement statement, ResultSet resultSet) { + if(resultSet != null) { + try { + resultSet.close(); + } catch(SQLException e) { + log.error("关闭ResultSet对象异常", e); + } + } + if(statement != null) { + try { + statement.close(); + } catch(SQLException e) { + log.error("关闭Statement对象异常", e); + } + } + // 注意:这里不关闭连接 + if(conn != null) { + try { + conn.close(); + tl.remove(); + } catch(SQLException e) { + log.error("关闭Connection对象异常", e); + } + } + } - /** - * - *

创建数据库连接

- * @author: zzs - * @date: 2019年8月31日 下午9:27:03 - * @return: Connection - * @throws SQLException - */ - private static Connection createConnection() throws SQLException { - Connection conn = null; - // 获得连接 - conn = dataSource.getConnection(); - return conn; - } + /** + * + *

创建数据库连接

+ * @author: zzs + * @date: 2019年8月31日 下午9:27:03 + * @return: Connection + * @throws SQLException + */ + private static Connection createConnection() throws SQLException { + Connection conn = null; + // 获得连接 + conn = dataSource.getConnection(); + return conn; + } - /** - *

根据指定配置文件创建数据源对象

- * @author: zzs - * @date: 2019年9月1日 上午10:53:05 - * @return: void - * @throws Exception - */ - private static void init() { - // 导入配置文件 - Properties properties = new Properties(); - InputStream in = JDBCUtils.class.getClassLoader().getResourceAsStream("dbcp.properties"); - try { - properties.load(in); - // 根据配置文件内容获得数据源对象 - dataSource = BasicDataSourceFactory.createDataSource(properties); - } catch(Exception ex) { - throw new RuntimeException("根据指定配置文件创建数据源出错", ex); - } - } + /** + *

根据指定配置文件创建数据源对象

+ * @author: zzs + * @date: 2019年9月1日 上午10:53:05 + * @return: void + * @throws Exception + */ + private static void init() { + // 导入配置文件 + Properties properties = new Properties(); + InputStream in = JDBCUtils.class.getClassLoader().getResourceAsStream("dbcp.properties"); + try { + properties.load(in); + // 根据配置文件内容获得数据源对象 + dataSource = BasicDataSourceFactory.createDataSource(properties); + } catch(Exception ex) { + throw new RuntimeException("根据指定配置文件创建数据源出错", ex); + } + } } diff --git a/src/test/java/cn/zzs/dbcp/BasicDataSourceTest.java b/src/test/java/cn/zzs/dbcp/BasicDataSourceTest.java index 97322a0..fa9cf94 100644 --- a/src/test/java/cn/zzs/dbcp/BasicDataSourceTest.java +++ b/src/test/java/cn/zzs/dbcp/BasicDataSourceTest.java @@ -15,126 +15,126 @@ import org.junit.Test; */ public class BasicDataSourceTest { - /** - *

测试添加用户

- * @throws SQLException - */ - @Test - public void save() throws SQLException { - // 创建sql - String sql = "insert into demo_user values(null,?,?,?,?,?)"; - Connection connection = null; - PreparedStatement statement = null; - try { - // 获得连接 - connection = JDBCUtils.getConnection(); - // 开启事务设置非自动提交 - connection.setAutoCommit(false); - // 获得Statement对象 - statement = connection.prepareStatement(sql); - // 设置参数 - statement.setString(1, "zzf003"); - statement.setInt(2, 18); - statement.setDate(3, new Date(System.currentTimeMillis())); - statement.setDate(4, new Date(System.currentTimeMillis())); - statement.setBoolean(5, false); - // 执行 - statement.executeUpdate(); - // 提交事务 - connection.commit(); - } finally { - // 释放资源 - JDBCUtils.release(connection, statement, null); - } - } + /** + *

测试添加用户

+ * @throws SQLException + */ + @Test + public void save() throws SQLException { + // 创建sql + String sql = "insert into demo_user values(null,?,?,?,?,?)"; + Connection connection = null; + PreparedStatement statement = null; + try { + // 获得连接 + connection = JDBCUtils.getConnection(); + // 开启事务设置非自动提交 + connection.setAutoCommit(false); + // 获得Statement对象 + statement = connection.prepareStatement(sql); + // 设置参数 + statement.setString(1, "zzf003"); + statement.setInt(2, 18); + statement.setDate(3, new Date(System.currentTimeMillis())); + statement.setDate(4, new Date(System.currentTimeMillis())); + statement.setBoolean(5, false); + // 执行 + statement.executeUpdate(); + // 提交事务 + connection.commit(); + } finally { + // 释放资源 + JDBCUtils.release(connection, statement, null); + } + } - /** - *

测试更新用户

- * @throws SQLException - */ - @Test - public void update() throws SQLException { - // 创建sql - String sql = "update demo_user set age = ?,gmt_modified = ? where name = ?"; - Connection connection = null; - PreparedStatement statement = null; - try { - // 获得连接 - connection = JDBCUtils.getConnection(); - // 开启事务 - connection.setAutoCommit(false); - // 获得Statement对象 - statement = connection.prepareStatement(sql); - // 设置参数 - statement.setInt(1, 19); - statement.setDate(2, new Date(System.currentTimeMillis())); - statement.setString(3, "zzf003"); - // 执行 - statement.executeUpdate(); - // 提交事务 - connection.commit(); - } finally { - // 释放资源 - JDBCUtils.release(connection, statement, null); - } - } + /** + *

测试更新用户

+ * @throws SQLException + */ + @Test + public void update() throws SQLException { + // 创建sql + String sql = "update demo_user set age = ?,gmt_modified = ? where name = ?"; + Connection connection = null; + PreparedStatement statement = null; + try { + // 获得连接 + connection = JDBCUtils.getConnection(); + // 开启事务 + connection.setAutoCommit(false); + // 获得Statement对象 + statement = connection.prepareStatement(sql); + // 设置参数 + statement.setInt(1, 19); + statement.setDate(2, new Date(System.currentTimeMillis())); + statement.setString(3, "zzf003"); + // 执行 + statement.executeUpdate(); + // 提交事务 + connection.commit(); + } finally { + // 释放资源 + JDBCUtils.release(connection, statement, null); + } + } - /** - *

测试查找用户

- * @throws SQLException - */ - @Test - public void findAll() throws SQLException { - // 创建sql - String sql = "select * from demo_user where deleted = false"; - Connection connection = null; - PreparedStatement statement = null; - ResultSet resultSet = null; - try { - // 获得连接 - connection = JDBCUtils.getConnection(); - // 获得Statement对象 - statement = connection.prepareStatement(sql); - // 执行 - resultSet = statement.executeQuery(); - // 遍历结果集 - while(resultSet.next()) { - String name = resultSet.getString(2); - int age = resultSet.getInt(3); - System.out.println("用户名:" + name + ",年龄:" + age); - } - } finally { - // 释放资源 - JDBCUtils.release(connection, statement, resultSet); - } - } + /** + *

测试查找用户

+ * @throws SQLException + */ + @Test + public void findAll() throws SQLException { + // 创建sql + String sql = "select * from demo_user where deleted = false"; + Connection connection = null; + PreparedStatement statement = null; + ResultSet resultSet = null; + try { + // 获得连接 + connection = JDBCUtils.getConnection(); + // 获得Statement对象 + statement = connection.prepareStatement(sql); + // 执行 + resultSet = statement.executeQuery(); + // 遍历结果集 + while(resultSet.next()) { + String name = resultSet.getString(2); + int age = resultSet.getInt(3); + System.out.println("用户名:" + name + ",年龄:" + age); + } + } finally { + // 释放资源 + JDBCUtils.release(connection, statement, resultSet); + } + } + + /** + *

测试删除用户

+ */ + @Test + public void delete() throws Exception { + // 创建sql + String sql = "delete from demo_user where name = ?"; + Connection connection = null; + PreparedStatement statement = null; + try { + // 获得连接 + connection = JDBCUtils.getConnection(); + // 设置非自动提交 + connection.setAutoCommit(false); + // 获得Statement对象 + statement = connection.prepareStatement(sql); + // 设置参数 + statement.setString(1, "zzf003"); + // 执行 + statement.executeUpdate(); + // 提交事务 + connection.commit(); + } finally { + // 释放资源 + JDBCUtils.release(connection, statement, null); + } + } - /** - *

测试删除用户

- */ - @Test - public void delete() throws Exception { - // 创建sql - String sql = "delete from demo_user where name = ?"; - Connection connection = null; - PreparedStatement statement = null; - try { - // 获得连接 - connection = JDBCUtils.getConnection(); - // 设置非自动提交 - connection.setAutoCommit(false); - // 获得Statement对象 - statement = connection.prepareStatement(sql); - // 设置参数 - statement.setString(1, "zzf003"); - // 执行 - statement.executeUpdate(); - // 提交事务 - connection.commit(); - } finally { - // 释放资源 - JDBCUtils.release(connection, statement, null); - } - } - } diff --git a/src/test/java/cn/zzs/dbcp/BasicManagedDataSourceTest.java b/src/test/java/cn/zzs/dbcp/BasicManagedDataSourceTest.java index 78f061c..b2db09d 100644 --- a/src/test/java/cn/zzs/dbcp/BasicManagedDataSourceTest.java +++ b/src/test/java/cn/zzs/dbcp/BasicManagedDataSourceTest.java @@ -17,91 +17,78 @@ import com.atomikos.icatch.jta.UserTransactionManager; */ public class BasicManagedDataSourceTest { - public BasicManagedDataSource getBasicManagedDataSource( - TransactionManager transactionManager, - String url, - String username, - String password) { - BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource(); - basicManagedDataSource.setTransactionManager(transactionManager); - basicManagedDataSource.setUrl(url); - basicManagedDataSource.setUsername(username); - basicManagedDataSource.setPassword(password); - basicManagedDataSource.setDefaultAutoCommit(false); - basicManagedDataSource.setXADataSource("com.mysql.cj.jdbc.MysqlXADataSource"); - return basicManagedDataSource; - } + public BasicManagedDataSource getBasicManagedDataSource(TransactionManager transactionManager, String url, String username, String password) { + BasicManagedDataSource basicManagedDataSource = new BasicManagedDataSource(); + basicManagedDataSource.setTransactionManager(transactionManager); + basicManagedDataSource.setUrl(url); + basicManagedDataSource.setUsername(username); + basicManagedDataSource.setPassword(password); + basicManagedDataSource.setDefaultAutoCommit(false); + basicManagedDataSource.setXADataSource("com.mysql.cj.jdbc.MysqlXADataSource"); + return basicManagedDataSource; + } - @Test - public void test01() throws Exception { - // 获得事务管理器 - TransactionManager transactionManager = new UserTransactionManager(); - - // 获取第一个数据库的数据源 - BasicManagedDataSource basicManagedDataSource1 = getBasicManagedDataSource( - transactionManager, - "jdbc:mysql://localhost:3306/github_demo?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=true", - "root", - "root"); - // 注意,这一步非常重要 - basicManagedDataSource1.setDefaultCatalog("github_demo"); - - // 获取第二个数据库的数据源 - BasicManagedDataSource basicManagedDataSource2 = getBasicManagedDataSource( - transactionManager, - "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=true", - "zzf", - "zzf"); - // 注意,这一步非常重要 - basicManagedDataSource1.setDefaultCatalog("test"); - - - Connection connection1 = null; - Statement statement1 = null; - Connection connection2 = null; - Statement statement2 = null; - transactionManager.begin(); - try { - // 获取连接并进行数据库操作,这里会将会将XAResource注册到当前线程的XA事务对象 - /** - * XA START xid1;-- 启动一个事务,并使之为active状态 - */ - connection1 = basicManagedDataSource1.getConnection(); - statement1 = connection1.createStatement(); - /** - * update github_demo.demo_user set deleted = 1 where id = '1'; -- 事务中的语句 - */ - boolean result1 = statement1.execute("update github_demo.demo_user set deleted = 1 where id = '1'"); - System.out.println(result1); - - /** - * XA START xid2;-- 启动一个事务,并使之为active状态 - */ - connection2 = basicManagedDataSource2.getConnection(); - statement2 = connection2.createStatement(); - /** - * update test.demo_user set deleted = 1 where id = '1'; -- 事务中的语句 - */ - boolean result2 = statement2.execute("update test.demo_user set deleted = 1 where id = '1'"); - System.out.println(result2); - - /** - * 当这执行以下语句: - * XA END xid1; -- 把事务置为idle状态 - * XA PREPARE xid1; -- 把事务置为prepare状态 - * XA END xid2; -- 把事务置为idle状态 - * XA PREPARE xid2; -- 把事务置为prepare状态 - * XA COMMIT xid1; -- 提交事务 - * XA COMMIT xid2; -- 提交事务 - */ - transactionManager.commit(); - } catch(Exception e) { - e.printStackTrace(); - } finally { - statement1.close(); - statement2.close(); - connection1.close(); - connection2.close(); - } - } + @Test + public void test01() throws Exception { + // 获得事务管理器 + TransactionManager transactionManager = new UserTransactionManager(); + + // 获取第一个数据库的数据源 + BasicManagedDataSource basicManagedDataSource1 = getBasicManagedDataSource(transactionManager, "jdbc:mysql://localhost:3306/github_demo?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=true", "root", "root"); + // 注意,这一步非常重要 + basicManagedDataSource1.setDefaultCatalog("github_demo"); + + // 获取第二个数据库的数据源 + BasicManagedDataSource basicManagedDataSource2 = getBasicManagedDataSource(transactionManager, "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=true", "zzf", "zzf"); + // 注意,这一步非常重要 + basicManagedDataSource1.setDefaultCatalog("test"); + + Connection connection1 = null; + Statement statement1 = null; + Connection connection2 = null; + Statement statement2 = null; + transactionManager.begin(); + try { + // 获取连接并进行数据库操作,这里会将会将XAResource注册到当前线程的XA事务对象 + /** + * XA START xid1;-- 启动一个事务,并使之为active状态 + */ + connection1 = basicManagedDataSource1.getConnection(); + statement1 = connection1.createStatement(); + /** + * update github_demo.demo_user set deleted = 1 where id = '1'; -- 事务中的语句 + */ + boolean result1 = statement1.execute("update github_demo.demo_user set deleted = 1 where id = '1'"); + System.out.println(result1); + + /** + * XA START xid2;-- 启动一个事务,并使之为active状态 + */ + connection2 = basicManagedDataSource2.getConnection(); + statement2 = connection2.createStatement(); + /** + * update test.demo_user set deleted = 1 where id = '1'; -- 事务中的语句 + */ + boolean result2 = statement2.execute("update test.demo_user set deleted = 1 where id = '1'"); + System.out.println(result2); + + /** + * 当这执行以下语句: + * XA END xid1; -- 把事务置为idle状态 + * XA PREPARE xid1; -- 把事务置为prepare状态 + * XA END xid2; -- 把事务置为idle状态 + * XA PREPARE xid2; -- 把事务置为prepare状态 + * XA COMMIT xid1; -- 提交事务 + * XA COMMIT xid2; -- 提交事务 + */ + transactionManager.commit(); + } catch(Exception e) { + e.printStackTrace(); + } finally { + statement1.close(); + statement2.close(); + connection1.close(); + connection2.close(); + } + } }