JDBC 核心功能与实践技巧全解析,涵盖数据库连接管理、PreparedStatement
与 Statement 的对比、事务控制、转账案例实现及 Druid
连接池的配置与优化,助力高效构建 Java
数据访问层并提升数据库操作性能。
1 JDBC概念
jdbc概念总结
- jdbc是(Java Database
Connectivity)单词的缩写,翻译为java连接数据库
- jdbc是java程序连接数据库的技术统称
- jdbc由java语言的规范(接口)和各个数据库厂商的实现驱动(jar)组成
- jdbc是一种典型的面向接口编程
- jdbc优势
- 只需要学习jdbc规范接口的方法,即可操作所有的数据库软件
- 项目中期切换数据库软件,只需要更换对应的数据库驱动jar包,不需要更改代码
2 JDBC API使用
DriverManager获取连接;接着建立连接;PreparedStatement(最常用)发送sql语句;若是查询操作,则对应的查询结果放在Result中。
- DriverManager
- 将第三方数据库厂商的实现驱动jar注册到程序中
- 可以根据数据库连接信息获取connection
- Connection [建立连接]
- 和数据库建立的连接,在连接对象上,可以多次执行数据库curd动作
- 可以获取statement和 preparedstatement,callablestatement对象
- Statement【适用静态sql路线 没有动态值的】 |
PreparedStatement【预编译sql 有动态值语句】 |
CallableStatement
- 具体发送SQL语句到数据库管理软件的对象
- 不同发送方式稍有不同! preparedstatement
使用为重点!
- Result【对查询语句才有】(查询的结果)
- 面向对象思维的产物(抽象成数据库的查询结果表)
- 存储DQL查询数据库结果的对象
- 需要我们进行解析,获取具体的数据库数据
具体步骤如下:
- 注册驱动【依赖的jar包 进行安装】
- 获取连接【connection建立连接】
- 创建发送sql语句对象【statement 创建发送sql语句的statement】
- 发送sql语句,并获取返回结果【statement发送sql语句到数据库
并且取得返回结构】
- 结果集解析【将result结果解析出来】
- 资源关闭【释放resultset、statement、connection】
基于statement
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public static void main(String[] args) throws SQLException { DriverManager.registerDriver(new Driver()); Connection connection = DriverManager.getConnection("jdbc:mysql://192.168.74.131:3306/test", "root", "root1234"); Statement statement = connection.createStatement(); String sql = "select id,account,password,nickname from t_user ;"; ResultSet resultSet = statement.executeQuery(sql); while (resultSet.next()){ int id = resultSet.getInt("id"); String account = resultSet.getString("account"); String password = resultSet.getString("password"); String nickname = resultSet.getString("nickname"); System.out.println(id+"::"+account+"::"+password+"::"+nickname); } resultSet.close(); statement.close(); connection.close(); }
|
模拟账户登陆
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
| public class JdbcStatementLoginPart {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Scanner scanner = new Scanner(System.in); String account = scanner.nextLine(); String password = scanner.nextLine(); scanner.close();
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu", "root", "root");
Statement statement = connection.createStatement();
String sql = "select * from t_user where account = '"+account+"' and password = '"+password+"' ;";
ResultSet resultSet = statement.executeQuery(sql);
if (resultSet.next()){ System.out.println("登录成功!"); }else{ System.out.println("登录失败!"); }
resultSet.close(); statement.close(); connection.close(); }
}
|
存在问题
SQL语句需要字符串拼接,比较麻烦(示例代码在:执行SQL语句
[动态SQL语句,需要字符串拼接])
只能拼接字符串类型,其他的数据库类型无法处理
可能发生注入攻击
动态值充当了SQL语句结构,影响了原有的查询结果!
基于PreparedStatement
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| public class JdbcPreparedStatementLoginPart {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
Scanner scanner = new Scanner(System.in); String account = scanner.nextLine(); String password = scanner.nextLine(); scanner.close();
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql:///atguigu", "root", "root");
String sql = "select * from t_user where account = ? and password = ? ;"; PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setObject(2,password); preparedStatement.setObject(1,account);
ResultSet resultSet = preparedStatement.executeQuery();
if (resultSet.next()){ System.out.println("登录成功!"); }else{ System.out.println("登录失败!"); }
resultSet.close(); preparedStatement.close(); connection.close(); }
}
|
使用总结
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| 方案1: 调用静态方法,但是会注册两次 DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver()); 方案2: 反射触发 Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection = DriverManager.getConnection();
3 (String url,String user,String password) 2 (String url,Properties info(user password)) 1 (String url?user=账号&password=密码 )
Statement statement = connection.createStatement();
PreparedStatement preparedstatement = connection.preparedStatement(sql语句结构);
preparedstatement.setObject(?的位置从左向右从1开始,?的值)
int rows = executeUpdate(); Resultset = executeQuery();
getColumnCount(); getCloumnLebal(index);
close();
|
3 全新JDBC扩展提升
自增长主键回显
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
|
@Test public void returnPrimaryKey() throws Exception{
Class.forName("com.mysql.cj.jdbc.Driver"); Connection connection = DriverManager.getConnection( "jdbc:mysql:///atguigu?user=root&password=root"); String sql = "insert into t_user (account,password,nickname) values (?,?,?);";
PreparedStatement statement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); statement.setObject(1,"towgog"); statement.setObject(2,"123456"); statement.setObject(3,"二狗子"); int i = statement.executeUpdate(); System.out.println("i = " + i);
ResultSet resultSet = statement.getGeneratedKeys(); resultSet.next(); int anInt = resultSet.getInt(1); System.out.println("anInt = " + anInt);
statement.close(); connection.close(); }
|
批量插入数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
|
@Test public void batchInsertYH() throws Exception{
Class.forName("com.mysql.cj.jdbc.Driver"); Connection connection = DriverManager.getConnection ("jdbc:mysql:///atguigu?rewriteBatchedStatements=true","root","root"); String sql = "insert into t_user (account,password,nickname) values (?,?,?)";
long start = System.currentTimeMillis(); PreparedStatement statement = connection.prepareStatement(sql); for (int i = 0; i < 10000; i++) {
statement.setObject(1,"ergouzi"+i); statement.setObject(2,"lvdandan"); statement.setObject(3,"驴蛋蛋"+i); statement.addBatch(); }
statement.executeBatch();
long end = System.currentTimeMillis();
System.out.println("消耗时间:"+(end - start));
connection.close(); }
|
事务实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| 数据库事务就是一种SQL语句执行的缓存机制,不会单条执行完毕就更新数据库数据,最终根据缓 存内的多条语句执行结果统一判定! 一个事务内所有语句都成功及事务成功,我们可以触发commit提交事务来结束事务,更新数据! 一个事务内任意一条语句失败,及事务失败,我们可以触发rollback回滚结束事务, 数据回到事务之前状态! 举个例子: 临近高考,你好吃懒做,偶尔还瞎花钱,父母也只会说'你等着!',待到高考完毕! 成绩600+,翻篇,庆祝! 成绩200+,翻旧账,男女混合双打!
允许我们在失败情况下,数据回归到业务之前的状态!
**一个业务****涉及****多条修改****数据库语句!** 例如: 经典的转账案例,转账业务(加钱和减钱) 批量删除(涉及多个删除) 批量添加(涉及多个插入)
1. 原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生, 要么都不发生。
2. 一致性(Consistency)事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
3. 隔离性(Isolation)事务的隔离性是指一个事务的执行不能被其他事务干扰, 即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
4. 持久性(Durability)持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的, 接下来的其他操作和数据库故障不应该对其有任何影响
自动提交 : 每条语句自动存储一个事务中,执行成功自动提交,执行失败自动回滚! (MySQL) 手动提交: 手动开启事务,添加语句,手动提交或者手动回滚即可!
针对自动提交: 关闭自动提交即可,多条语句添加以后,最终手动提交或者回滚! (推荐) SET autocommit = off; # 只有当前连接有效 # 编写SQL语句即可 SQL SQL SQL #手动提交或者回滚 【结束当前的事务】 COMMIT / ROLLBACK ; 手动开启事务: 开启事务代码,添加SQL语句,事务提交或者事务回滚! (不推荐)
try{ connection.setAutoCommit(false); connection.commit(); }catch(Execption e){ connection.rollback(); }
|
1 2 3 4 5 6 7 8
| -- 继续在atguigu的库中创建银行表 CREATE TABLE t_bank( id INT PRIMARY KEY AUTO_INCREMENT COMMENT '账号主键', account VARCHAR(20) NOT NULL UNIQUE COMMENT '账号', money INT UNSIGNED COMMENT '金额,不能为负值') ; INSERT INTO t_bank(account,money) VALUES ('ergouzi',1000),('lvdandan',1000);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
public class BankTest {
@Test public void testBank() throws Exception { BankService bankService = new BankService(); bankService.transfer("ergouzi", "lvdandan", 500); }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
|
public class BankService {
public void transfer(String addAccount,String subAccount, int money) throws ClassNotFoundException, SQLException {
System.out.println("addAccount = " + addAccount + ", subAccount = " + subAccount + ", money = " + money);
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection = DriverManager.getConnection ("jdbc:mysql:///atguigu", "root", "root");
int flag = 0;
try { connection.setAutoCommit(false);
BankDao bankDao = new BankDao(); bankDao.addMoney(addAccount,money,connection); System.out.println("--------------"); bankDao.subMoney(subAccount,money,connection); flag = 1; connection.commit(); }catch (Exception e){
connection.rollback(); throw e; }finally { connection.close(); }
if (flag == 1){ System.out.println("转账成功!"); }else{ System.out.println("转账失败!"); } }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
public class BankDao {
public int addMoney(String account, int money,Connection connection) throws ClassNotFoundException, SQLException {
String sql = "update t_bank set money = money + ? where account = ? ;"; PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setObject(1, money); preparedStatement.setString(2, account);
int rows = preparedStatement.executeUpdate();
System.out.println("加钱执行完毕!");
preparedStatement.close();
return rows; }
public int subMoney(String account, int money,Connection connection) throws ClassNotFoundException, SQLException {
String sql = "update t_bank set money = money - ? where account = ? ;"; PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setObject(1, money); preparedStatement.setString(2, account);
int rows = preparedStatement.executeUpdate();
System.out.println("减钱执行完毕!");
preparedStatement.close();
return rows; } }
|
4 国货之光Druid
4.1连接性能消耗问题分析
4.2 数据库连接池作用
总结缺点:
(1)不使用数据库连接池,每次都通过DriverManager获取新连接,用完直接抛弃断开,
连接的利用率太低,太浪费。
(2)对于数据库服务器来说,压力太大了。我们数据库服务器和Java程序对连接数也无法控制
,很容易导致数据库服务器崩溃。
我们就希望能管理连接。
- 我们可以建立一个连接池,这个池中可以容纳一定数量的连接对象,一开始,
我们可以先替用户先创建好一些连接对象,等用户要拿连接对象时,就直接从池中拿,
不用新建了,这样也可以节省时间。然后用户用完后,放回去,别人可以接着用。
- 可以提高连接的使用率。当池中的现有的连接都用完了,那么连接池可以向服务器申
请新的连接放到池中。
- 直到池中的连接达到“最大连接数”,就不能在申请新的连接了,如果没有拿到连接的用户只能等待。
4.3市面常见连接池产品和对比
JDBC 的数据库连接池使用
javax.sql.DataSource接口进行规范,所有的第三方连接池都实现此接口,自行添加具体实现!也就是说,所有连接池获取连接的和回收连接方法都一样,不同的只有性能和扩展功能!
DBCP
是Apache提供的数据库连接池,速度相对c3p0较快,但因自身存在BUG
C3P0
是一个开源组织提供的一个数据库连接池,速度相对较慢,稳定性还可以
Proxool
是sourceforge下的一个开源项目数据库连接池,有监控连接池状态的功能,稳定性较c3p0差一点
Druid 是阿里提供的数据库连接池,据说是集DBCP 、C3P0 、Proxool
优点于一身 的数据库连接池,妥妥国货之光!!!!
4.4国货之光 druid连接池使用
记得导入druid工具类jar
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
|
@Test public void druidHard() throws SQLException { DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); dataSource.setUsername("root"); dataSource.setPassword("root"); dataSource.setUrl("jdbc:mysql:///day01"); dataSource.setInitialSize(5); 初始化数量 dataSource.setMaxActive(10); 最大数量 Connection connection = dataSource.getConnection(); connection.close(); }
|
软编码方式
外部配置存放在src/druid.properties
1 2 3 4 5
| # druid连接池需要的配置参数,key固定命名 driverClassName=com.mysql.cj.jdbc.Driver username=root password=root url=jdbc:mysql:///atguigu
|
1 2 3 4 5 6 7 8 9 10 11 12 13
|
@Test
public void druidSoft() throws Exception { Properties properties = new Properties(); InputStream ips = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties"); properties.load(ips); DataSource dataSource = DruidDataSourceFactory.createDataSource(properties); }
|
配置 |
缺省 |
说明 |
name |
|
配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。
如果没有配置,将会生成一个名字,格式是:”DataSource-” +
System.identityHashCode(this) |
jdbcUrl |
|
连接数据库的url,不同数据库不一样。例如:mysql :
jdbc:mysql://10.20.153.104:3306/druid2 oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto |
username |
|
连接数据库的用户名 |
password |
|
连接数据库的密码。如果你不希望密码直接写在配置文件中,可以使用ConfigFilter。详细看这里:https://github.com/alibaba/druid/wiki/%E4%BD%BF%E7%94%A8ConfigFilter |
driverClassName |
|
根据url自动识别
这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName(建议配置下) |
initialSize |
0 |
初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时 |
maxActive |
8 |
最大连接池数量 |
maxIdle |
8 |
已经不再使用,配置了也没效果 |
minIdle |
|
最小连接池数量 |
maxWait |
|
获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。 |
poolPreparedStatements |
false |
是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。 |
maxOpenPreparedStatements |
-1 |
要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100 |
validationQuery |
|
用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。 |
testOnBorrow |
true |
申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 |
testOnReturn |
false |
归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 |
testWhileIdle |
false |
建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 |
timeBetweenEvictionRunsMillis |
|
有两个含义: 1) Destroy线程会检测连接的间隔时间 2)
testWhileIdle的判断依据,详细看testWhileIdle属性的说明 |
numTestsPerEvictionRun |
|
不再使用,一个DruidDataSource只支持一个EvictionRun |
minEvictableIdleTimeMillis |
|
|
connectionInitSqls |
|
物理连接初始化的时候执行的sql |
exceptionSorter |
|
根据dbType自动识别 当数据库抛出一些不可恢复的异常时,抛弃连接 |
filters |
|
属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有:
监控统计用的filter:stat日志用的filter:log4j防御sql注入的filter:wall |
proxyFilters |
|
类型是List,如果同时配置了filters和proxyFilters,是组合关系,并非替换关系 |
5
全新JDBC使用优化以及工具类封装
过程:1.注册驱动 2.获取连接 3.编写SQL语句 4.创建statement
5.占位符赋值 6.发送SQL语句 7.结果解析 8.回收资源
下面v1.0和v2.0针对128进行封装
BaseDao针对34567进行封装,进行增删改查
jdbc工具类封装v1.0
我们封装一个工具类,内部包含连接池对象,同时对外提供连接的方法和回收连接的方法!
外部配置文件
位置: src/druid.properties
1 2 3 4 5
| driverClassName=com.mysql.cj.jdbc.Driver username=root password=root url=jdbc:mysql:///atguigu
|
工具类代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties;
public class JDBCToolsVersion1 { private static DataSource ds; static{ try { Properties pro = new Properties(); pro.load(ClassLoader.getSystemResourceAsStream("druid.properties")); ds = DruidDataSourceFactory.createDataSource(pro); } catch (Exception e) { e.printStackTrace(); } }
public static Connection getConnection() throws SQLException { return ds.getConnection(); }
public static void free(Connection conn) throws SQLException { conn.setAutoCommit(true); conn.close(); } }
|
jdbc工具类封装v.2.0
优化工具类v1.0版本,考虑事务的情况下!如何一个线程的不同方法获取同一个连接!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| ThreadLocal的介绍: 线程本地变量:为同一个线程存储共享变量 JDK 1.2 的版本中就提供 java.lang.ThreadLocal,为解决多线程程序的并发问题提供了一种新的思路。 使用这个工具类可以很简洁地编写出优美的多线程程序。通常用来在在多线程中管理共享数据库连接、 Session等
ThreadLocal用于保存某个线程共享变量,原因是在Java中,每一个线程对象中都有一个 ThreadLocalMap<ThreadLocal, Object>,其key就是一个ThreadLocal,而Object即为该线程的 共享变量。而这个map是通过ThreadLocal的set和get方法操作的。对于同一个static ThreadLocal, 不同线程只能从中get,set,remove自己的变量,而不会影响其他线程的变量。
1、ThreadLocal对象.get: 获取ThreadLocal中当前线程共享变量的值。
2、ThreadLocal对象.set: 设置ThreadLocal中当前线程共享变量的值。
3、ThreadLocal对象.remove: 移除ThreadLocal中当前线程共享变量的值。
|
v2.0版本工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties;
public class JDBCTools { private static DataSource ds; private static ThreadLocal<Connection> tl = new ThreadLocal<>(); static{ try { Properties pro = new Properties(); pro.load(ClassLoader.getSystemResourceAsStream("druid.properties")); ds = DruidDataSourceFactory.createDataSource(pro); } catch (Exception e) { e.printStackTrace(); } }
public static Connection getConnection() throws SQLException { Connection connection = tl.get(); if(connection == null){ connection = ds.getConnection(); tl.set(connection); } return connection; }
public static void free() throws SQLException { Connection connection = tl.get(); if(connection != null){ tl.remove(); connection.setAutoCommit(true); connection.close(); } } }
|
高级应用层封装BaseDao
基本上每一个数据表都应该有一个对应的DAO接口及其实现类,发现对所有表的操作(增、删、改、查)代码重复度很高,所以可以抽取公共代码,给这些DAO的实现类可以抽取一个公共的父类,我们称为BaseDao
针对DQL查询和非DQL进行,分成两类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
| public abstract class BaseDao {
protected int update(String sql,Object... args) throws SQLException {
Connection connection = JDBCTools.getConnection(); PreparedStatement ps = connection.prepareStatement(sql); if(args != null && args.length>0){ for(int i=0; i<args.length; i++) { ps.setObject(i+1, args[i]); } }
int len = ps.executeUpdate(); ps.close(); if (connection.getAutoCommit()) { JDBCTools.free(); } return len; }
protected <T> ArrayList<T> query(Class<T> clazz,String sql, Object... args) throws Exception { Connection connection = JDBCTools.getConnection(); PreparedStatement ps = connection.prepareStatement(sql); if(args != null && args.length>0){ for(int i=0; i<args.length; i++) { ps.setObject(i+1, args[i]); } }
ArrayList<T> list = new ArrayList<>(); ResultSet res = ps.executeQuery();
ResultSetMetaData metaData = res.getMetaData(); int columnCount = metaData.getColumnCount();
while(res.next()){ T t = clazz.newInstance();
for(int i=1; i<=columnCount; i++){ Object value = res.getObject(i);
String columnName = metaData.getColumnLabel(i); Field field = clazz.getDeclaredField(columnName); field.setAccessible(true);
field.set(t, value); }
list.add(t); }
res.close(); ps.close(); if (connection.getAutoCommit()) { JDBCTools.free(); } return list; }
protected <T> T queryBean(Class<T> clazz,String sql, Object... args) throws Exception { ArrayList<T> list = query(clazz, sql, args); if(list == null || list.size() == 0){ return null; } return list.get(0); } }
|