| @@ -0,0 +1,37 @@ | |||||
| # maven ignore | |||||
| target/ | |||||
| *.jar | |||||
| !.mvn/wrapper/* | |||||
| *.war | |||||
| *.zip | |||||
| *.tar | |||||
| *.tar.gz | |||||
| # eclipse ignore | |||||
| .settings/ | |||||
| .project | |||||
| .classpath | |||||
| # idea ignore | |||||
| .idea/ | |||||
| *.ipr | |||||
| *.iml | |||||
| *.iws | |||||
| # temp ignore | |||||
| *.log | |||||
| *.cache | |||||
| *.diff | |||||
| *.patch | |||||
| *.tmp | |||||
| # system ignore | |||||
| .DS_Store | |||||
| Thumbs.db | |||||
| *.orig | |||||
| # flatten ignore | |||||
| .flattened-pom.xml | |||||
| # license check result | |||||
| license-list | |||||
| @@ -0,0 +1,478 @@ | |||||
| # DBCP | |||||
| ## 简介 | |||||
| DBCP用于创建和管理连接,利用连接池的方式复用连接减少了资源开销。 | |||||
| 连接池的参数可以采用`properties`文件来配置:配置包括驱动、链接、账号密码,连接池基本参数,事务相关参数,连接测试的参数以及内存回收参数等。 | |||||
| DBCP对外交互主要是一个`BasicDataDource`,用于设置连接池参数和获取连接对象,作用有点类似于JDK的`DriverManager`。通过源码可以看到,`BasicDataSource`内部有一个`dataSource` 和`connectionPool`字段。 | |||||
| `dataSource`用于从连接池中获取连接。 | |||||
| `connectionPool`用于创建,存储和管理池中的连接,里面有一个`Map`对象和`LinkedBlockingDeque`对象,分别存储着所有连接和空闲连接,构成所谓的“池”。 | |||||
| ## 使用例子 | |||||
| ### 需求 | |||||
| 使用DBCP连接池获取连接对象,对用户数据进行增删改查。 | |||||
| ### 工程环境 | |||||
| JDK:1.8.0_201 | |||||
| maven:3.6.1 | |||||
| IDE:Spring Tool Suites4 for Eclipse | |||||
| mysql驱动:8.0.15 | |||||
| mysql:5.7 | |||||
| ### 主要步骤 | |||||
| DBCP对外交互主要是一个`BasicDataDource`,用于设置连接池参数和获取连接对象。 | |||||
| 1. 通过`BasicDataSourceFactory.createDataSource(properties)`设置连接池参数,并获得`BasicDataDource`对象; | |||||
| 2. 获取连接对象:调用`BasicDataDource`对象的`getConnection()`方法获取`Connection`对象。 | |||||
| ### 创建表 | |||||
| ```sql | |||||
| CREATE DATABASE `demo`CHARACTER SET utf8 COLLATE utf8_bin; | |||||
| User `demo`; | |||||
| CREATE TABLE `user` ( | |||||
| `id` tinyint(3) unsigned NOT NULL AUTO_INCREMENT COMMENT '用户id', | |||||
| `name` varchar(32) COLLATE utf8_bin NOT NULL COMMENT '用户名', | |||||
| `age` int(10) unsigned DEFAULT NULL COMMENT '用户年龄', | |||||
| `gmt_create` datetime DEFAULT NULL COMMENT '记录创建时间', | |||||
| `gmt_modified` datetime DEFAULT NULL COMMENT '记录最后修改时间', | |||||
| PRIMARY KEY (`id`), | |||||
| UNIQUE KEY `uk_name` (`name`) | |||||
| ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; | |||||
| ``` | |||||
| ### 创建项目 | |||||
| 项目类型Maven Project,打包方式jar | |||||
| ### 引入依赖 | |||||
| ```xml | |||||
| <!-- junit --> | |||||
| <dependency> | |||||
| <groupId>junit</groupId> | |||||
| <artifactId>junit</artifactId> | |||||
| <version>4.12</version> | |||||
| <scope>test</scope> | |||||
| </dependency> | |||||
| <!-- dbcp --> | |||||
| <dependency> | |||||
| <groupId>org.apache.commons</groupId> | |||||
| <artifactId>commons-dbcp2</artifactId> | |||||
| <version>2.6.0</version> | |||||
| </dependency> | |||||
| <!-- log4j --> | |||||
| <dependency> | |||||
| <groupId>log4j</groupId> | |||||
| <artifactId>log4j</artifactId> | |||||
| <version>1.2.17</version> | |||||
| </dependency> | |||||
| <!-- mysql驱动的jar包 --> | |||||
| <dependency> | |||||
| <groupId>mysql</groupId> | |||||
| <artifactId>mysql-connector-java</artifactId> | |||||
| <version>8.0.15</version> | |||||
| </dependency> | |||||
| ``` | |||||
| ### 编写jdbc.prperties | |||||
| 路径:resources目录下 | |||||
| ```properties | |||||
| #数据库配置 | |||||
| driverClassName=com.mysql.cj.jdbc.Driver | |||||
| url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=true | |||||
| username=root | |||||
| password=root | |||||
| ``` | |||||
| ### 编写JDBCUtil用于获得连接对象 | |||||
| 这里设置工具类的目的是避免多个线程使用同一个连接对象,并提供了释放资源的方法(注意,考虑到重用性,这里并不会关闭连接)。 | |||||
| 路径:`cn.zzs.jdbc` | |||||
| ```java | |||||
| /** | |||||
| * @ClassName: JDBCUtil | |||||
| * @Description: 用于获取数据库连接对象的工具类 | |||||
| * @author: zzs | |||||
| * @date: 2019年8月31日 下午9:05:08 | |||||
| */ | |||||
| public class JDBCUtil { | |||||
| private static DataSource dataSource; | |||||
| private static ThreadLocal<Connection> tl = new ThreadLocal<>(); | |||||
| private static Object obj = new Object(); | |||||
| static { | |||||
| init(); | |||||
| } | |||||
| /** | |||||
| * | |||||
| * @Title: getConnection | |||||
| * @Description: 获取数据库连接对象的方法,线程安全 | |||||
| * @author: zzs | |||||
| * @date: 2019年8月31日 下午9:22:29 | |||||
| * @return: Connection | |||||
| */ | |||||
| public static Connection getConnection(){ | |||||
| //从当前线程中获取连接对象 | |||||
| Connection connection = tl.get(); | |||||
| //判断为空的话,创建连接并绑定到当前线程 | |||||
| if(connection == null) { | |||||
| synchronized (obj) { | |||||
| if(tl.get() == null) { | |||||
| connection = createConnection(); | |||||
| tl.set(connection); | |||||
| } | |||||
| } | |||||
| } | |||||
| return connection; | |||||
| } | |||||
| /** | |||||
| * | |||||
| * @Title: release | |||||
| * @Description: 释放资源 | |||||
| * @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) { | |||||
| System.err.println("关闭ResultSet对象异常"); | |||||
| e.printStackTrace(); | |||||
| } | |||||
| } | |||||
| if(statement != null) { | |||||
| try { | |||||
| statement.close(); | |||||
| } catch (SQLException e) { | |||||
| System.err.println("关闭Statement对象异常"); | |||||
| e.printStackTrace(); | |||||
| } | |||||
| } | |||||
| //注意:这里不关闭连接 | |||||
| if(conn!=null) { | |||||
| try { | |||||
| //如果连接失效的话,从当前线程的绑定中删除 | |||||
| if(!conn.isValid(3)) { | |||||
| tl.remove(); | |||||
| } | |||||
| } catch (SQLException e) { | |||||
| System.err.println("校验连接有效性"); | |||||
| e.printStackTrace(); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * | |||||
| * @Title: createConnection | |||||
| * @Description: 创建数据库连接 | |||||
| * @author: zzs | |||||
| * @date: 2019年8月31日 下午9:27:03 | |||||
| * @return: Connection | |||||
| */ | |||||
| private static Connection createConnection(){ | |||||
| Connection conn = null; | |||||
| //获得连接 | |||||
| try { | |||||
| conn = dataSource.getConnection(); | |||||
| } catch (SQLException e) { | |||||
| System.err.println("从数据源获取连接失败"); | |||||
| e.printStackTrace(); | |||||
| } | |||||
| return conn; | |||||
| } | |||||
| /** | |||||
| * @Title: init | |||||
| * @Description: 根据指定配置文件创建数据源对象 | |||||
| * @author: zzs | |||||
| * @date: 2019年9月1日 上午10:53:05 | |||||
| * @return: void | |||||
| */ | |||||
| private static void init() { | |||||
| //导入配置文件 | |||||
| Properties properties = new Properties(); | |||||
| InputStream in = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties"); | |||||
| try { | |||||
| properties.load(in); | |||||
| //根据配置文件内容获得数据源对象 | |||||
| dataSource = BasicDataSourceFactory.createDataSource(properties); | |||||
| } catch (IOException e) { | |||||
| System.err.println("导入配置文件出错"); | |||||
| e.printStackTrace(); | |||||
| } catch (Exception e) { | |||||
| System.err.println("根据指定配置文件创建数据源出错"); | |||||
| e.printStackTrace(); | |||||
| } | |||||
| } | |||||
| } | |||||
| ``` | |||||
| ### 编写测试类 | |||||
| 路径:test目录下的`cn.zzs.jdbc` | |||||
| #### 添加用户 | |||||
| 注意:这里引入了事务 | |||||
| ```java | |||||
| /** | |||||
| * 测试添加用户 | |||||
| * @throws SQLException | |||||
| */ | |||||
| @Test | |||||
| public void saveUser() throws Exception { | |||||
| //创建sql | |||||
| String sql = "insert into user values(null,?,?,?,?)"; | |||||
| //获得连接 | |||||
| Connection connection = JDBCUtil.getConnection(); | |||||
| PreparedStatement statement = null; | |||||
| try { | |||||
| //设置非自动提交 | |||||
| connection.setAutoCommit(false); | |||||
| //获得Statement对象 | |||||
| statement = connection.prepareStatement(sql); | |||||
| //设置参数 | |||||
| statement.setString(1, "zzs001"); | |||||
| statement.setInt(2, 18); | |||||
| statement.setDate(3, new Date(System.currentTimeMillis())); | |||||
| statement.setDate(4, new Date(System.currentTimeMillis())); | |||||
| //执行 | |||||
| statement.executeUpdate(); | |||||
| //提交事务 | |||||
| connection.commit(); | |||||
| } catch (Exception e) { | |||||
| System.out.println("异常导致操作回滚"); | |||||
| connection.rollback(); | |||||
| e.printStackTrace(); | |||||
| } finally { | |||||
| //释放资源 | |||||
| JDBCUtil.release(connection, statement,null); | |||||
| } | |||||
| } | |||||
| ``` | |||||
| #### 更新用户 | |||||
| ```java | |||||
| /** | |||||
| * 测试更新用户 | |||||
| */ | |||||
| @Test | |||||
| public void updateUser() throws Exception { | |||||
| //创建sql | |||||
| String sql = "update user set age = ?,gmt_modified = ? where name = ?"; | |||||
| //获得连接 | |||||
| Connection connection = JDBCUtil.getConnection(); | |||||
| PreparedStatement statement = null; | |||||
| try { | |||||
| //设置非自动提交 | |||||
| connection.setAutoCommit(false); | |||||
| //获得Statement对象 | |||||
| statement = connection.prepareStatement(sql); | |||||
| //设置参数 | |||||
| statement.setInt(1, 19); | |||||
| statement.setDate(2, new Date(System.currentTimeMillis())); | |||||
| statement.setString(3, "zzs001"); | |||||
| //执行 | |||||
| statement.executeUpdate(); | |||||
| //提交事务 | |||||
| connection.commit(); | |||||
| } catch (Exception e) { | |||||
| System.out.println("异常导致操作回滚"); | |||||
| connection.rollback(); | |||||
| e.printStackTrace(); | |||||
| } finally { | |||||
| //释放资源 | |||||
| JDBCUtil.release(connection, statement,null); | |||||
| } | |||||
| } | |||||
| ``` | |||||
| #### 查询用户 | |||||
| ```java | |||||
| /** | |||||
| * 测试查找用户 | |||||
| */ | |||||
| @Test | |||||
| public void findUser() throws Exception { | |||||
| //创建sql | |||||
| String sql = "select * from user where name = ?"; | |||||
| //获得连接 | |||||
| Connection connection = JDBCUtil.getConnection(); | |||||
| PreparedStatement statement = null; | |||||
| ResultSet resultSet = null; | |||||
| try { | |||||
| //获得Statement对象 | |||||
| statement = connection.prepareStatement(sql); | |||||
| //设置参数 | |||||
| statement.setString(1, "zzs001"); | |||||
| //执行 | |||||
| resultSet = statement.executeQuery(); | |||||
| //遍历结果集 | |||||
| while (resultSet.next()) { | |||||
| String name = resultSet.getString(2); | |||||
| int age = resultSet.getInt(3); | |||||
| System.out.println("用户名:" + name + ",年龄:" + age); | |||||
| } | |||||
| } finally { | |||||
| //释放资源 | |||||
| JDBCUtil.release(connection, statement,resultSet); | |||||
| } | |||||
| } | |||||
| ``` | |||||
| #### 删除用户 | |||||
| ```java | |||||
| /** | |||||
| * 测试删除用户 | |||||
| */ | |||||
| @Test | |||||
| public void deleteUser() throws Exception { | |||||
| //创建sql | |||||
| String sql = "delete from user where name = ?"; | |||||
| //获得连接 | |||||
| Connection connection = JDBCUtil.getConnection(); | |||||
| PreparedStatement statement = null; | |||||
| try { | |||||
| //设置非自动提交 | |||||
| connection.setAutoCommit(false); | |||||
| //获得Statement对象 | |||||
| statement = connection.prepareStatement(sql); | |||||
| //设置参数 | |||||
| statement.setString(1, "zzs001"); | |||||
| //执行 | |||||
| statement.executeUpdate(); | |||||
| //提交事务 | |||||
| connection.commit(); | |||||
| } catch (Exception e) { | |||||
| System.out.println("异常导致操作回滚"); | |||||
| connection.rollback(); | |||||
| e.printStackTrace(); | |||||
| } finally { | |||||
| //释放资源 | |||||
| JDBCUtil.release(connection, statement,null); | |||||
| } | |||||
| } | |||||
| ``` | |||||
| ### dbcp配置文件详解 | |||||
| #### 数据库基本配置 | |||||
| ```properties | |||||
| driverClassName=com.mysql.cj.jdbc.Driver | |||||
| url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=true | |||||
| username=root | |||||
| password=root | |||||
| ``` | |||||
| #### 连接数据相关参数 | |||||
| ```properties | |||||
| #-------------连接数据相关参数-------------------------------- | |||||
| #初始化连接:连接池启动时创建的初始化连接数量 | |||||
| #默认为0 | |||||
| initialSize=0 | |||||
| #最大活动连接 | |||||
| #连接池在同一时间能够分配的最大活动连接的数量, 如果设置为非正数则表示不限制 | |||||
| #默认为8 | |||||
| maxActive=8 | |||||
| #最大空闲连接 | |||||
| #连接池中容许保持空闲状态的最大连接数量,超过的空闲连接将被释放,如果设置为负数表示不限制 | |||||
| #默认为8 | |||||
| maxIdle=8 | |||||
| #最小空闲连接 | |||||
| #连接池中容许保持空闲状态的最小连接数量,低于这个数量将创建新的连接,如果设置为0则不创建 | |||||
| #默认为0 | |||||
| minIdle=0 | |||||
| #最大等待时间 | |||||
| #当没有可用连接时,连接池等待连接被归还的最大时间(以毫秒计数),超过时间则抛出异常,如果设置为-1表示无限等待 | |||||
| #默认无限 | |||||
| maxWait=-1 | |||||
| ``` | |||||
| #### 事务相关的属性 | |||||
| ```properties | |||||
| #-------------事务相关的属性-------------------------------- | |||||
| #连接池创建的连接的默认的auto-commit状态 | |||||
| #默认为true | |||||
| defaultAutoCommit=false | |||||
| #连接池创建的连接的默认的read-only状态. 如果没有设置则setReadOnly方法将不会被调用. (某些驱动不支持只读模式,比如:Informix) | |||||
| #默认值由驱动决定 | |||||
| #defaultReadOnly=false | |||||
| #连接池创建的连接的默认的TransactionIsolation状态 | |||||
| #可用值为下列之一:NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE | |||||
| #默认值由驱动决定 | |||||
| defaultTransactionIsolation=REPEATABLE_READ | |||||
| #连接池创建的连接的默认的catalog | |||||
| #defaultCatalog | |||||
| ``` | |||||
| #### 连接检查情况 | |||||
| ```properties | |||||
| #-------------连接检查情况-------------------------------- | |||||
| #SQL查询,用来验证从连接池取出的连接,在将连接返回给调用者之前.如果指定,则查询必须是一个SQL SELECT并且必须返回至少一行记录 | |||||
| validationQuery= select 1 | |||||
| #指明是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个. | |||||
| #注意: 设置为true后如果要生效,validationQuery参数必须设置为非空字符串 | |||||
| #默认为true | |||||
| testOnBorrow=true | |||||
| #指明是否在归还到池中前进行检验 | |||||
| #注意: 设置为true后如果要生效,validationQuery参数必须设置为非空字符串 | |||||
| #默认为false | |||||
| testOnReturn=false | |||||
| #是否开启空闲资源监测。 | |||||
| #注意: 设置为true后如果要生效,validationQuery参数必须设置为非空字符串 | |||||
| #默认为false | |||||
| testWhileIdle= true | |||||
| #空闲资源的检测周期(单位为毫秒)。默认-1:不检测。建议设置,周期自行选择。timeBetweenEvictionRunsMillis=30000 | |||||
| #做空闲资源检测时,每次的采样数。默认3。 | |||||
| #可根据自身应用连接数进行微调,如果设置为-1,就是对所有连接做空闲监测。 | |||||
| numTestsPerEvictionRun=3 | |||||
| #资源池中资源最小空闲时间(单位为毫秒),达到此值后空闲资源将被移除。 | |||||
| #默认值1000*60*30 = 30分钟。建议默认,或根据自身业务选择。 | |||||
| minEvictableIdleTimeMillis=1800000 | |||||
| ``` | |||||
| #### 缓存语句 | |||||
| ```properties | |||||
| #-------------缓存语句-------------------------------- | |||||
| #开启池的prepared statement 池功能 | |||||
| #注意: 确认连接还有剩余资源可以留给其他statement | |||||
| #默认为false | |||||
| poolPreparedStatements=false | |||||
| #statement池能够同时分配的打开的statements的最大数量, 如果设置为0表示不限制 | |||||
| #默认为0 | |||||
| maxOpenPreparedStatements=0 | |||||
| ``` | |||||
| #### 连接泄漏回收参数 | |||||
| ```properties | |||||
| #-------------连接泄漏回收参数-------------------------------- | |||||
| #标记是否删除泄露的连接,如果他们超过了removeAbandonedTimout的限制. | |||||
| #如果设置为true, 连接被认为是被泄露并且可以被删除,如果空闲时间超过removeAbandonedTimeout. | |||||
| #设置为true可以为写法糟糕的没有关闭连接的程序修复数据库连接. | |||||
| #默认为false | |||||
| removeAbandoned=false | |||||
| #泄露的连接可以被删除的超时值, 单位秒 | |||||
| #默认为300 | |||||
| removeAbandonedTimeout=300 | |||||
| #标记当Statement或连接被泄露时是否打印程序的stack traces日志。 | |||||
| #被泄露的Statements和连接的日志添加在每个连接打开或者生成新的Statement,因为需要生成stack trace。 | |||||
| #默认为false | |||||
| logAbandoned=false | |||||
| #如果开启"removeAbandoned",那么连接在被认为泄露时可能被池回收. | |||||
| #这个机制在(getNumIdle() < 2) and (getNumActive() > getMaxActive() - 3)时被触发. | |||||
| #举例当maxActive=20, 活动连接为18,空闲连接为1时可以触发"removeAbandoned". | |||||
| #但是活动连接只有在没有被使用的时间超过"removeAbandonedTimeout"时才被删除,默认300秒.在resultset中游历不被计算为被使用. | |||||
| ``` | |||||
| #### 其他 | |||||
| ```properties | |||||
| #-------------其他-------------------------------- | |||||
| #控制PoolGuard是否容许获取底层连接 | |||||
| #默认为false | |||||
| accessToUnderlyingConnectionAllowed=false | |||||
| #如果容许则可以使用下面的方式来获取底层物理连接: | |||||
| # Connection conn = ds.getConnection(); | |||||
| # Connection dconn = ((DelegatingConnection) conn).getInnermostDelegate(); | |||||
| # ... | |||||
| # conn.close(); | |||||
| ``` | |||||
| > 学习使我快乐!! | |||||
| @@ -0,0 +1,38 @@ | |||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" | |||||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | |||||
| <modelVersion>4.0.0</modelVersion> | |||||
| <groupId>cn.zzs.dbcp</groupId> | |||||
| <artifactId>DBCP-demo</artifactId> | |||||
| <packaging>jar</packaging> | |||||
| <version>1.0.0</version> | |||||
| <name>DBCP-demo</name> | |||||
| <url>http://maven.apache.org</url> | |||||
| <dependencies> | |||||
| <!-- junit --> | |||||
| <dependency> | |||||
| <groupId>junit</groupId> | |||||
| <artifactId>junit</artifactId> | |||||
| <version>4.12</version> | |||||
| <scope>test</scope> | |||||
| </dependency> | |||||
| <!-- dbcp --> | |||||
| <dependency> | |||||
| <groupId>org.apache.commons</groupId> | |||||
| <artifactId>commons-dbcp2</artifactId> | |||||
| <version>2.6.0</version> | |||||
| </dependency> | |||||
| <!-- log4j --> | |||||
| <dependency> | |||||
| <groupId>log4j</groupId> | |||||
| <artifactId>log4j</artifactId> | |||||
| <version>1.2.17</version> | |||||
| </dependency> | |||||
| <!-- mysql驱动的jar包 --> | |||||
| <dependency> | |||||
| <groupId>mysql</groupId> | |||||
| <artifactId>mysql-connector-java</artifactId> | |||||
| <version>8.0.15</version> | |||||
| </dependency> | |||||
| </dependencies> | |||||
| </project> | |||||
| @@ -0,0 +1,136 @@ | |||||
| package cn.zzs.dbcp; | |||||
| import java.io.IOException; | |||||
| import java.io.InputStream; | |||||
| import java.sql.Connection; | |||||
| import java.sql.ResultSet; | |||||
| import java.sql.SQLException; | |||||
| import java.sql.Statement; | |||||
| import java.util.Properties; | |||||
| import javax.sql.DataSource; | |||||
| import org.apache.commons.dbcp2.BasicDataSourceFactory; | |||||
| /** | |||||
| * @ClassName: JDBCUtil | |||||
| * @Description: 用于获取数据库连接对象的工具类 | |||||
| * @author: zzs | |||||
| * @date: 2019年8月31日 下午9:05:08 | |||||
| */ | |||||
| public class JDBCUtil { | |||||
| private static DataSource dataSource; | |||||
| private static ThreadLocal<Connection> tl = new ThreadLocal<>(); | |||||
| private static Object obj = new Object(); | |||||
| static { | |||||
| init(); | |||||
| } | |||||
| /** | |||||
| * | |||||
| * @Title: getConnection | |||||
| * @Description: 获取数据库连接对象的方法,线程安全 | |||||
| * @author: zzs | |||||
| * @date: 2019年8月31日 下午9:22:29 | |||||
| * @return: Connection | |||||
| */ | |||||
| public static Connection getConnection(){ | |||||
| //从当前线程中获取连接对象 | |||||
| Connection connection = tl.get(); | |||||
| //判断为空的话,创建连接并绑定到当前线程 | |||||
| if(connection == null) { | |||||
| synchronized (obj) { | |||||
| if(tl.get() == null) { | |||||
| connection = createConnection(); | |||||
| tl.set(connection); | |||||
| } | |||||
| } | |||||
| } | |||||
| return connection; | |||||
| } | |||||
| /** | |||||
| * | |||||
| * @Title: release | |||||
| * @Description: 释放资源 | |||||
| * @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) { | |||||
| System.err.println("关闭ResultSet对象异常"); | |||||
| e.printStackTrace(); | |||||
| } | |||||
| } | |||||
| if(statement != null) { | |||||
| try { | |||||
| statement.close(); | |||||
| } catch (SQLException e) { | |||||
| System.err.println("关闭Statement对象异常"); | |||||
| e.printStackTrace(); | |||||
| } | |||||
| } | |||||
| //注意:这里不关闭连接 | |||||
| if(conn!=null) { | |||||
| try { | |||||
| //如果连接失效的话,从当前线程的绑定中删除 | |||||
| if(!conn.isValid(3)) { | |||||
| tl.remove(); | |||||
| } | |||||
| } catch (SQLException e) { | |||||
| System.err.println("校验连接有效性"); | |||||
| e.printStackTrace(); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * | |||||
| * @Title: createConnection | |||||
| * @Description: 创建数据库连接 | |||||
| * @author: zzs | |||||
| * @date: 2019年8月31日 下午9:27:03 | |||||
| * @return: Connection | |||||
| */ | |||||
| private static Connection createConnection(){ | |||||
| Connection conn = null; | |||||
| //获得连接 | |||||
| try { | |||||
| conn = dataSource.getConnection(); | |||||
| } catch (SQLException e) { | |||||
| System.err.println("从数据源获取连接失败"); | |||||
| e.printStackTrace(); | |||||
| } | |||||
| return conn; | |||||
| } | |||||
| /** | |||||
| * @Title: init | |||||
| * @Description: 根据指定配置文件创建数据源对象 | |||||
| * @author: zzs | |||||
| * @date: 2019年9月1日 上午10:53:05 | |||||
| * @return: void | |||||
| */ | |||||
| private static void init() { | |||||
| //导入配置文件 | |||||
| Properties properties = new Properties(); | |||||
| InputStream in = JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties"); | |||||
| try { | |||||
| properties.load(in); | |||||
| //根据配置文件内容获得数据源对象 | |||||
| dataSource = BasicDataSourceFactory.createDataSource(properties); | |||||
| } catch (IOException e) { | |||||
| System.err.println("导入配置文件出错"); | |||||
| e.printStackTrace(); | |||||
| } catch (Exception e) { | |||||
| System.err.println("根据指定配置文件创建数据源出错"); | |||||
| e.printStackTrace(); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,100 @@ | |||||
| #数据库基本配置 | |||||
| driverClassName=com.mysql.cj.jdbc.Driver | |||||
| url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=true | |||||
| username=root | |||||
| password=root | |||||
| #-------------连接数据相关参数-------------------------------- | |||||
| #初始化连接:连接池启动时创建的初始化连接数量 | |||||
| #默认为0 | |||||
| initialSize=0 | |||||
| #最大活动连接 | |||||
| #连接池在同一时间能够分配的最大活动连接的数量, 如果设置为非正数则表示不限制 | |||||
| #默认为8 | |||||
| maxActive=8 | |||||
| #最大空闲连接 | |||||
| #连接池中容许保持空闲状态的最大连接数量,超过的空闲连接将被释放,如果设置为负数表示不限制 | |||||
| #默认为8 | |||||
| maxIdle=8 | |||||
| #最小空闲连接 | |||||
| #连接池中容许保持空闲状态的最小连接数量,低于这个数量将创建新的连接,如果设置为0则不创建 | |||||
| #默认为0 | |||||
| minIdle=0 | |||||
| #最大等待时间 | |||||
| #当没有可用连接时,连接池等待连接被归还的最大时间(以毫秒计数),超过时间则抛出异常,如果设置为-1表示无限等待 | |||||
| #默认无限 | |||||
| maxWait=-1 | |||||
| #-------------事务相关的属性-------------------------------- | |||||
| #连接池创建的连接的默认的auto-commit状态 | |||||
| #默认为true | |||||
| defaultAutoCommit=false | |||||
| #连接池创建的连接的默认的read-only状态. 如果没有设置则setReadOnly方法将不会被调用. (某些驱动不支持只读模式,比如:Informix) | |||||
| #默认值由驱动决定 | |||||
| #defaultReadOnly=false | |||||
| #连接池创建的连接的默认的TransactionIsolation状态 | |||||
| #可用值为下列之一:NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE | |||||
| #默认值由驱动决定 | |||||
| defaultTransactionIsolation=REPEATABLE_READ | |||||
| #连接池创建的连接的默认的catalog | |||||
| #defaultCatalog | |||||
| #-------------连接检查情况-------------------------------- | |||||
| #SQL查询,用来验证从连接池取出的连接,在将连接返回给调用者之前.如果指定,则查询必须是一个SQL SELECT并且必须返回至少一行记录 | |||||
| validationQuery= select 1 | |||||
| #指明是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个. | |||||
| #注意: 设置为true后如果要生效,validationQuery参数必须设置为非空字符串 | |||||
| #默认为true | |||||
| testOnBorrow=true | |||||
| #指明是否在归还到池中前进行检验 | |||||
| #注意: 设置为true后如果要生效,validationQuery参数必须设置为非空字符串 | |||||
| #默认为false | |||||
| testOnReturn=false | |||||
| #是否开启空闲资源监测。 | |||||
| #注意: 设置为true后如果要生效,validationQuery参数必须设置为非空字符串 | |||||
| #默认为false | |||||
| testWhileIdle= true | |||||
| #空闲资源的检测周期(单位为毫秒)。默认-1:不检测。建议设置,周期自行选择。timeBetweenEvictionRunsMillis=30000 | |||||
| #做空闲资源检测时,每次的采样数。默认3。 | |||||
| #可根据自身应用连接数进行微调,如果设置为-1,就是对所有连接做空闲监测。 | |||||
| numTestsPerEvictionRun=3 | |||||
| #资源池中资源最小空闲时间(单位为毫秒),达到此值后空闲资源将被移除。 | |||||
| #默认值1000*60*30 = 30分钟。建议默认,或根据自身业务选择。 | |||||
| minEvictableIdleTimeMillis=1800000 | |||||
| #-------------缓存语句-------------------------------- | |||||
| #开启池的prepared statement 池功能 | |||||
| #注意: 确认连接还有剩余资源可以留给其他statement | |||||
| #默认为false | |||||
| poolPreparedStatements=false | |||||
| #statement池能够同时分配的打开的statements的最大数量, 如果设置为0表示不限制 | |||||
| #默认为0 | |||||
| maxOpenPreparedStatements=0 | |||||
| #-------------连接泄漏回收参数-------------------------------- | |||||
| #标记是否删除泄露的连接,如果他们超过了removeAbandonedTimout的限制. | |||||
| #如果设置为true, 连接被认为是被泄露并且可以被删除,如果空闲时间超过removeAbandonedTimeout. | |||||
| #设置为true可以为写法糟糕的没有关闭连接的程序修复数据库连接. | |||||
| #默认为false | |||||
| removeAbandoned=false | |||||
| #泄露的连接可以被删除的超时值, 单位秒 | |||||
| #默认为300 | |||||
| removeAbandonedTimeout=300 | |||||
| #标记当Statement或连接被泄露时是否打印程序的stack traces日志。 | |||||
| #被泄露的Statements和连接的日志添加在每个连接打开或者生成新的Statement,因为需要生成stack trace。 | |||||
| #默认为false | |||||
| logAbandoned=false | |||||
| #如果开启"removeAbandoned",那么连接在被认为泄露时可能被池回收. | |||||
| #这个机制在(getNumIdle() < 2) and (getNumActive() > getMaxActive() - 3)时被触发. | |||||
| #举例当maxActive=20, 活动连接为18,空闲连接为1时可以触发"removeAbandoned". | |||||
| #但是活动连接只有在没有被使用的时间超过"removeAbandonedTimeout"时才被删除,默认300秒.在resultset中游历不被计算为被使用. | |||||
| #-------------其他-------------------------------- | |||||
| #控制PoolGuard是否容许获取底层连接 | |||||
| #默认为false | |||||
| accessToUnderlyingConnectionAllowed=false | |||||
| #如果容许则可以使用下面的方式来获取底层物理连接: | |||||
| # Connection conn = ds.getConnection(); | |||||
| # Connection dconn = ((DelegatingConnection) conn).getInnermostDelegate(); | |||||
| # ... | |||||
| # conn.close(); | |||||
| @@ -0,0 +1,183 @@ | |||||
| #OFF,systemOut,logFile,logDailyFile,logRollingFile,logMail,logDB,ALL | |||||
| #①配置根Logger | |||||
| log4j.rootLogger=debug,systemOut | |||||
| #OFF,systemOut,logFile,logDailyFile,logRollingFile,logMail,logDB,ALL | |||||
| #②配置其他Logger | |||||
| #log4j.logger.myLogger=debug,systemOut | |||||
| #log4j.additivity.mobileLogger=false | |||||
| #输出到控制台 | |||||
| log4j.appender.systemOut= org.apache.log4j.ConsoleAppender | |||||
| log4j.appender.systemOut.layout= org.apache.log4j.PatternLayout | |||||
| log4j.appender.systemOut.layout.ConversionPattern=[%p][Thread:%t]: %m%n | |||||
| log4j.appender.systemOut.Threshold= debug | |||||
| log4j.appender.systemOut.ImmediateFlush= TRUE | |||||
| log4j.appender.systemOut.Target= System.out | |||||
| #输出到文件 | |||||
| log4j.appender.logFile= org.apache.log4j.FileAppender | |||||
| log4j.appender.logFile.layout= org.apache.log4j.PatternLayout | |||||
| log4j.appender.logFile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread:%t][Class:%c Method: %M]%n%p: %m%n | |||||
| log4j.appender.logFile.Threshold= DEBUG | |||||
| log4j.appender.logFile.ImmediateFlush= TRUE | |||||
| log4j.appender.logFile.Append= TRUE | |||||
| log4j.appender.logFile.File= logs/file_log.log | |||||
| log4j.appender.logFile.Encoding= utf-8 | |||||
| #按DatePattern输出到文件 | |||||
| log4j.appender.logDailyFile= org.apache.log4j.DailyRollingFileAppender | |||||
| log4j.appender.logDailyFile.layout= org.apache.log4j.PatternLayout | |||||
| log4j.appender.logDailyFile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread:%t][Class:%c Method: %M]%n%p: %m%n | |||||
| #[%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l]%n%m%n | |||||
| log4j.appender.logDailyFile.Threshold= warn | |||||
| log4j.appender.logDailyFile.ImmediateFlush= TRUE | |||||
| log4j.appender.logDailyFile.Append= TRUE | |||||
| log4j.appender.logDailyFile.File= logs/daily_log | |||||
| log4j.appender.logDailyFile.DatePattern= '_'yyyy-MM-dd-HH-mm'.log' | |||||
| log4j.appender.logDailyFile.Encoding= utf-8 | |||||
| #设定文件大小输出到文件 | |||||
| log4j.appender.logRollingFile= org.apache.log4j.RollingFileAppender | |||||
| log4j.appender.logRollingFile.layout= org.apache.log4j.PatternLayout | |||||
| log4j.appender.logRollingFile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread:%t][Class:%c Method: %M]%n%p: %m%n | |||||
| log4j.appender.logRollingFile.Threshold= DEBUG | |||||
| log4j.appender.logRollingFile.ImmediateFlush= TRUE | |||||
| log4j.appender.logRollingFile.Append= TRUE | |||||
| log4j.appender.logRollingFile.File=logs/rolling_log.log | |||||
| log4j.appender.logRollingFile.MaxFileSize= 1mb | |||||
| log4j.appender.logRollingFile.MaxBackupIndex= 10 | |||||
| log4j.appender.logRollingFile.Encoding= utf-8 | |||||
| #用Email发送日志 | |||||
| log4j.appender.logMail= org.apache.log4j.net.SMTPAppender | |||||
| log4j.appender.logMail.layout= org.apache.log4j.HTMLLayout | |||||
| log4j.appender.logMail.layout.LocationInfo= TRUE | |||||
| log4j.appender.logMail.layout.Title= My Mail LogFile | |||||
| log4j.appender.logMail.Threshold= DEBUG | |||||
| log4j.appender.logMail.SMTPDebug= FALSE | |||||
| log4j.appender.logMail.SMTPHost= SMTP.163.com | |||||
| log4j.appender.logMail.From= zzs@163.com | |||||
| log4j.appender.logMail.To= zzs@gmail.com | |||||
| #log4j.appender.logMail.Cc= xly3000@gmail.com | |||||
| #log4j.appender.logMail.Bcc= xly3000@gmail.com | |||||
| log4j.appender.logMail.SMTPUsername= zzs | |||||
| log4j.appender.logMail.SMTPPassword= zzs | |||||
| log4j.appender.logMail.Subject= Log4j Log Messages | |||||
| #log4j.appender.logMail.BufferSize= 1024 | |||||
| #log4j.appender.logMail.SMTPAuth= TRUE | |||||
| #将日志登录到MySQL数据库 | |||||
| log4j.appender.logDB= org.apache.log4j.jdbc.JDBCAppender | |||||
| log4j.appender.logDB.layout= org.apache.log4j.PatternLayout | |||||
| log4j.appender.logDB.Driver= com.mysql.cj.jdbc.Driver | |||||
| log4j.appender.logDB.URL= jdbc:mysql://127.0.0.1:3306/crm_logs?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=true | |||||
| log4j.appender.logDB.User= root | |||||
| log4j.appender.logDB.Password= root | |||||
| log4j.appender.logDB.Sql= INSERT INTO T_log4j(project_name,create_date,level,category,file_name,thread_name,line,all_category,message)values('Struts2','%d{yyyy-MM-ddHH:mm:ss}','%p','%c','%F','%t','%L','%l','%m') | |||||
| ################################################################################ | |||||
| #①配置根Logger,其语法为: | |||||
| # | |||||
| #log4j.rootLogger =[level],appenderName,appenderName2,... | |||||
| #level是日志记录的优先级,分为OFF,TRACE,DEBUG,INFO,WARN,ERROR,FATAL,ALL | |||||
| ##Log4j建议只使用四个级别,优先级从低到高分别是DEBUG,INFO,WARN,ERROR | |||||
| #通过在这里定义的级别,您可以控制到应用程序中相应级别的日志信息的开关 | |||||
| #比如在这里定义了INFO级别,则应用程序中所有DEBUG级别的日志信息将不被打印出来 | |||||
| #appenderName就是指定日志信息输出到哪个地方。可同时指定多个输出目的 | |||||
| ################################################################################ | |||||
| ################################################################################ | |||||
| #②配置日志信息输出目的地Appender,其语法为: | |||||
| # | |||||
| #log4j.appender.appenderName =fully.qualified.name.of.appender.class | |||||
| #log4j.appender.appenderName.optionN =valueN | |||||
| # | |||||
| #Log4j提供的appender有以下几种: | |||||
| #1)org.apache.log4j.ConsoleAppender(输出到控制台) | |||||
| #2)org.apache.log4j.FileAppender(输出到文件) | |||||
| #3)org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件) | |||||
| #4)org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件) | |||||
| #5)org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方) | |||||
| # | |||||
| #1)ConsoleAppender选项属性 | |||||
| # -Threshold = DEBUG:指定日志消息的输出最低层次 | |||||
| # -ImmediateFlush = TRUE:默认值是true,所有的消息都会被立即输出 | |||||
| # -Target = System.err:默认值System.out,输出到控制台(err为红色,out为黑色) | |||||
| # | |||||
| #2)FileAppender选项属性 | |||||
| # -Threshold = INFO:指定日志消息的输出最低层次 | |||||
| # -ImmediateFlush = TRUE:默认值是true,所有的消息都会被立即输出 | |||||
| # -File = C:\log4j.log:指定消息输出到C:\log4j.log文件 | |||||
| # -Append = FALSE:默认值true,将消息追加到指定文件中,false指将消息覆盖指定的文件内容 | |||||
| # -Encoding = UTF-8:可以指定文件编码格式 | |||||
| # | |||||
| #3)DailyRollingFileAppender选项属性 | |||||
| #-Threshold = WARN:指定日志消息的输出最低层次 | |||||
| #-ImmediateFlush = TRUE:默认值是true,所有的消息都会被立即输出 | |||||
| # -File =C:\log4j.log:指定消息输出到C:\log4j.log文件 | |||||
| # -Append= FALSE:默认值true,将消息追加到指定文件中,false指将消息覆盖指定的文件内容 | |||||
| #-DatePattern='.'yyyy-ww:每周滚动一次文件,即每周产生一个新的文件。还可以按用以下参数: | |||||
| # '.'yyyy-MM:每月 | |||||
| # '.'yyyy-ww:每周 | |||||
| # '.'yyyy-MM-dd:每天 | |||||
| # '.'yyyy-MM-dd-a:每天两次 | |||||
| # '.'yyyy-MM-dd-HH:每小时 | |||||
| # '.'yyyy-MM-dd-HH-mm:每分钟 | |||||
| #-Encoding = UTF-8:可以指定文件编码格式 | |||||
| # | |||||
| #4)RollingFileAppender选项属性 | |||||
| #-Threshold = ERROR:指定日志消息的输出最低层次 | |||||
| #-ImmediateFlush = TRUE:默认值是true,所有的消息都会被立即输出 | |||||
| # -File =C:/log4j.log:指定消息输出到C:/log4j.log文件 | |||||
| # -Append= FALSE:默认值true,将消息追加到指定文件中,false指将消息覆盖指定的文件内容 | |||||
| #-MaxFileSize = 100KB:后缀可以是KB,MB,GB.在日志文件到达该大小时,将会自动滚动.如:log4j.log.1 | |||||
| #-MaxBackupIndex = 2:指定可以产生的滚动文件的最大数 | |||||
| #-Encoding = UTF-8:可以指定文件编码格式 | |||||
| ################################################################################ | |||||
| ################################################################################ | |||||
| #③配置日志信息的格式(布局),其语法为: | |||||
| # | |||||
| #log4j.appender.appenderName.layout=fully.qualified.name.of.layout.class | |||||
| #log4j.appender.appenderName.layout.optionN= valueN | |||||
| # | |||||
| #Log4j提供的layout有以下几种: | |||||
| #5)org.apache.log4j.HTMLLayout(以HTML表格形式布局) | |||||
| #6)org.apache.log4j.PatternLayout(可以灵活地指定布局模式) | |||||
| #7)org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串) | |||||
| #8)org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息) | |||||
| #9)org.apache.log4j.xml.XMLLayout(以XML形式布局) | |||||
| # | |||||
| #5)HTMLLayout选项属性 | |||||
| #-LocationInfo = TRUE:默认值false,输出java文件名称和行号 | |||||
| #-Title=Struts Log Message:默认值 Log4JLog Messages | |||||
| # | |||||
| #6)PatternLayout选项属性 | |||||
| #-ConversionPattern = %m%n:格式化指定的消息(参数意思下面有) | |||||
| # | |||||
| #9)XMLLayout选项属性 | |||||
| #-LocationInfo = TRUE:默认值false,输出java文件名称和行号 | |||||
| # | |||||
| #Log4J采用类似C语言中的printf函数的打印格式格式化日志信息,打印参数如下: | |||||
| #%m 输出代码中指定的消息 | |||||
| #%p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL | |||||
| #%r 输出自应用启动到输出该log信息耗费的毫秒数 | |||||
| #%c 输出所属的类目,通常就是所在类的全名 | |||||
| #%t 输出产生该日志事件的线程名 | |||||
| #%n 输出一个回车换行符,Windows平台为“\r\n”,Unix平台为“\n” | |||||
| #%d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式 | |||||
| # 如:%d{yyyy年MM月dd日HH:mm:ss,SSS},输出类似:2012年01月05日 22:10:28,921 | |||||
| #%l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数 | |||||
| # 如:Testlog.main(TestLog.java:10) | |||||
| #%F 输出日志消息产生时所在的文件名称 | |||||
| #%L 输出代码中的行号 | |||||
| #%x 输出和当前线程相关联的NDC(嵌套诊断环境),像javaservlets多客户多线程的应用中 | |||||
| #%% 输出一个"%"字符 | |||||
| # | |||||
| # 可以在%与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式。如: | |||||
| # %5c: 输出category名称,最小宽度是5,category<5,默认的情况下右对齐 | |||||
| # %-5c:输出category名称,最小宽度是5,category<5,"-"号指定左对齐,会有空格 | |||||
| # %.5c:输出category名称,最大宽度是5,category>5,就会将左边多出的字符截掉,<5不会有空格 | |||||
| # %20.30c:category名称<20补空格,并且右对齐,>30字符,就从左边交远销出的字符截掉 | |||||
| ################################################################################ | |||||
| ################################################################################ | |||||
| #④指定特定包的输出特定的级别 | |||||
| #log4j.logger.org.springframework=DEBUG | |||||
| ################################################################################ | |||||
| @@ -0,0 +1,146 @@ | |||||
| package cn.zzs.dbcp; | |||||
| import java.sql.Connection; | |||||
| import java.sql.Date; | |||||
| import java.sql.PreparedStatement; | |||||
| import java.sql.ResultSet; | |||||
| import java.sql.SQLException; | |||||
| import org.junit.Test; | |||||
| /** | |||||
| * @ClassName: DBCPTest | |||||
| * @Description: 测试DBCP | |||||
| * @author: zzs | |||||
| * @date: 2019年8月31日 下午9:39:54 | |||||
| */ | |||||
| public class DBCPTest { | |||||
| /** | |||||
| * 测试添加用户 | |||||
| * @throws SQLException | |||||
| */ | |||||
| @Test | |||||
| public void saveUser() throws Exception { | |||||
| //创建sql | |||||
| String sql = "insert into user values(null,?,?,?,?)"; | |||||
| //获得连接 | |||||
| Connection connection = JDBCUtil.getConnection(); | |||||
| PreparedStatement statement = null; | |||||
| try { | |||||
| //设置非自动提交 | |||||
| connection.setAutoCommit(false); | |||||
| //获得Statement对象 | |||||
| statement = connection.prepareStatement(sql); | |||||
| //设置参数 | |||||
| statement.setString(1, "zzs001"); | |||||
| statement.setInt(2, 18); | |||||
| statement.setDate(3, new Date(System.currentTimeMillis())); | |||||
| statement.setDate(4, new Date(System.currentTimeMillis())); | |||||
| //执行 | |||||
| statement.executeUpdate(); | |||||
| //提交事务 | |||||
| connection.commit(); | |||||
| } catch (Exception e) { | |||||
| System.out.println("异常导致操作回滚"); | |||||
| connection.rollback(); | |||||
| e.printStackTrace(); | |||||
| } finally { | |||||
| //释放资源 | |||||
| JDBCUtil.release(connection, statement,null); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 测试更新用户 | |||||
| */ | |||||
| @Test | |||||
| public void updateUser() throws Exception { | |||||
| //创建sql | |||||
| String sql = "update user set age = ?,gmt_modified = ? where name = ?"; | |||||
| //获得连接 | |||||
| Connection connection = JDBCUtil.getConnection(); | |||||
| PreparedStatement statement = null; | |||||
| try { | |||||
| //设置非自动提交 | |||||
| connection.setAutoCommit(false); | |||||
| //获得Statement对象 | |||||
| statement = connection.prepareStatement(sql); | |||||
| //设置参数 | |||||
| statement.setInt(1, 19); | |||||
| statement.setDate(2, new Date(System.currentTimeMillis())); | |||||
| statement.setString(3, "zzs001"); | |||||
| //执行 | |||||
| statement.executeUpdate(); | |||||
| //提交事务 | |||||
| connection.commit(); | |||||
| } catch (Exception e) { | |||||
| System.out.println("异常导致操作回滚"); | |||||
| connection.rollback(); | |||||
| e.printStackTrace(); | |||||
| } finally { | |||||
| //释放资源 | |||||
| JDBCUtil.release(connection, statement,null); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 测试查找用户 | |||||
| */ | |||||
| @Test | |||||
| public void findUser() throws Exception { | |||||
| //创建sql | |||||
| String sql = "select * from user where name = ?"; | |||||
| //获得连接 | |||||
| Connection connection = JDBCUtil.getConnection(); | |||||
| PreparedStatement statement = null; | |||||
| ResultSet resultSet = null; | |||||
| try { | |||||
| //获得Statement对象 | |||||
| statement = connection.prepareStatement(sql); | |||||
| //设置参数 | |||||
| statement.setString(1, "zzs001"); | |||||
| //执行 | |||||
| resultSet = statement.executeQuery(); | |||||
| //遍历结果集 | |||||
| while (resultSet.next()) { | |||||
| String name = resultSet.getString(2); | |||||
| int age = resultSet.getInt(3); | |||||
| System.out.println("用户名:" + name + ",年龄:" + age); | |||||
| } | |||||
| } finally { | |||||
| //释放资源 | |||||
| JDBCUtil.release(connection, statement,resultSet); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * 测试删除用户 | |||||
| */ | |||||
| @Test | |||||
| public void deleteUser() throws Exception { | |||||
| //创建sql | |||||
| String sql = "delete from user where name = ?"; | |||||
| //获得连接 | |||||
| Connection connection = JDBCUtil.getConnection(); | |||||
| PreparedStatement statement = null; | |||||
| try { | |||||
| //设置非自动提交 | |||||
| connection.setAutoCommit(false); | |||||
| //获得Statement对象 | |||||
| statement = connection.prepareStatement(sql); | |||||
| //设置参数 | |||||
| statement.setString(1, "zzs001"); | |||||
| //执行 | |||||
| statement.executeUpdate(); | |||||
| //提交事务 | |||||
| connection.commit(); | |||||
| } catch (Exception e) { | |||||
| System.out.println("异常导致操作回滚"); | |||||
| connection.rollback(); | |||||
| e.printStackTrace(); | |||||
| } finally { | |||||
| //释放资源 | |||||
| JDBCUtil.release(connection, statement,null); | |||||
| } | |||||
| } | |||||
| } | |||||