JDBC
- sun公司提供的一套用于数据库操作的接口,java程序员只需要面向这套接口编程即可
- 不同的数据库厂商需要针对这套接口,提供不同的实现,不同的实现的集合,就是不同数据库的驱动——面向接口编程
JDBC的体系结构
面向应用的API:开发人员编程使用(链接数据库,执行SQL语句等)
面向数据库的API:供开发商数据库驱动程序用
链接方式
- 五种迭代
第五种
1.配置文件JDBC.properties
user=root
password=zmj.666.999
url=jdbc:mysql://localhost:3306/test?serverTimezone=UTC
driverClass=com.mysql.jdbc.Driver
2.JDBC_Connection.java
import org.junit.Test;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Properties;
/**
* Created by KingsLanding on 2022/6/4 16:17
*/
public class JDBC_Connection {
@Test
public void getConnection() throws Exception {
//读取配置文件中的4个基本信息
InputStream is = JDBC_Connection.class.getClassLoader().getResourceAsStream("JDBC.properties");
Properties pros = new Properties();
pros.load(is);
String user = pros.getProperty("user");
String password = pros.getProperty("password");
String url = pros.getProperty("url");
String driverClass = pros.getProperty("driverClass");
//2.加载驱动
Class.forName(driverClass);
//3.获取链接
Connection conn= DriverManager.getConnection(url,user,password);
System.out.println(conn);
}
}
Statement——>PreparedStatement
- Statement会导致SQL注入的问题,所以使用Statement的子接口PreparedStatement替换
数据插入
package statement;
import connection.JDBC_Connection;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
/**
* 使用PreparedStatement替换Statement实现对数据表的增删改查
*
* Created by KingsLanding on 2022/6/4 18:30
*/
public class PreparedStatement {
@Test
public void getConnection(){
//读取配置文件中的4个基本信息
Connection conn= null;
java.sql.PreparedStatement ps = null;
try {
InputStream is = PreparedStatement.class.getClassLoader().getResourceAsStream("JDBC.properties");
Properties pros = new Properties();
pros.load(is);
String user = pros.getProperty("user");
String password = pros.getProperty("password");
String url = pros.getProperty("url");
String driverClass = pros.getProperty("driverClass");
//2.加载驱动
Class.forName(driverClass);
//3.获取链接
conn = DriverManager.getConnection(url,user,password);
System.out.println(conn);//测试是否链接成功
//4.预编译sql语句,返回PreparedStatement实例
String sql="insert into user(id,username,password)value(?,?,?)";//?是占位符
ps = conn.prepareStatement(sql);
ps.setInt(1,3);
ps.setString(2,"张千一");
ps.setString(3,"190321435");
//6.执行操作
ps.execute();
} catch (Exception e) {
e.printStackTrace();
} finally {
//7.资源关闭
try {
if(conn!=null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(conn!=null);
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
JDBC_Util通用工具类
package jdbcUtil;
import org.junit.Test;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**JDBC链接和关闭工具类
* 静态方法能被类调用
* Created by KingsLanding on 2022/6/5 12:55
*/
public class JDBC_Util {
public static Connection getConnection() throws Exception{
//读取配置文件中的4个基本信息
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("JDBC.properties");
Properties pros = new Properties();
pros.load(is);
String user = pros.getProperty("user");
String password = pros.getProperty("password");
String url = pros.getProperty("url");
String driverClass = pros.getProperty("driverClass");
//2.加载驱动
Class.forName(driverClass);
//3.获取链接
Connection conn= DriverManager.getConnection(url,user,password);
System.out.println(conn);
return conn;
}
/**
* 关闭Connection和Statement
* @param conn
* @param ps
*/
public static void closeResource(Connection conn, Statement ps){
try {
if(conn!=null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(conn!=null);
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
调用工具类执行操作
package statement;
import jdbcUtil.JDBC_Util;
import org.junit.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
/**
* Created by KingsLanding on 2022/6/5 13:18
*/
public class PreparedStatementUpdate {
@Test
public void testUpdate() {
Connection conn= null;
java.sql.PreparedStatement ps = null;
//1.链接数据库
try {
conn = JDBC_Util.getConnection();//类调用数据库链接方法
//2.预编译sql语句,返回PreparedStatement实例
String sql="update user set username = ?,password = ? where id=3";
ps = conn.prepareStatement(sql);
//3.填充占位符
ps.setString(1,"张干一");
ps.setString(2,"1223000000");
//4.执行
ps.execute();
} catch (Exception e) {
e.printStackTrace();
} finally {
//5.资源关闭
JDBC_Util.closeResource(conn,ps);//类调用资源关闭方法
}
}
}
增删改通用
-
将sql和占位符以形参的方式在方法中定义
-
占位符用可变参数设置,for循环填入占位符
-
调用通用数据库操作方法,设置参数update(sql,args);
for(int i=0;i<args.length;i++){ //i+1是占位符位置,从1开始,args[i]是数据库属性名从0开始 ps.setObject(i+1,args[i]); }
package statement;
import jdbcUtil.JDBC_Util;
import org.junit.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
/**
* 通用的增删改操作
* Created by KingsLanding on 2022/6/5 14:26
*/
public class Update {
//可变形参...arg必须和sql中的占位符对应
public void update(String sql,Object ...args){
Connection conn =null;
PreparedStatement ps=null;
try {
//1.链接数据库
conn = JDBC_Util.getConnection();
//2.预编译sql语句,返回PreparedStatement实例
ps = conn.prepareStatement(sql);
//3.填充占位符
for(int i=0;i<args.length;i++){
//i+1是占位符位置,从1开始,args[i]是数据库属性名从0开始
ps.setObject(i+1,args[i]);
}
//4.执行
ps.execute();
} catch (Exception e) {
e.printStackTrace();
} finally {
//5.资源关闭
JDBC_Util.closeResource(conn,ps);
}
}
//插入数据操作
@Test
public void insert(){
String sql="insert into user(id,username,password)value(?,?,?)";
update(sql,5,"张明均","1902421140");
}
@Test
//删除数据操作
public void delete(){
String sql="delete from user where id=?";
update(sql,2);
}
/**
@Test
//删除数据操作
public void delete(){
String sql="delete from user where id=?";
Object[] args={1};
update(sql,args);
}
*/
}
javaBean
- 1、根据数据表结构定义响应数据类型的对象
- 2、无参构造器
- 3、有参构造器
- 4、get() set()方法
- 5、toString()方法
ORM编程思想(Object,relational,mapping)
package user;
/**
* Created by KingsLanding on 2022/6/4 18:39
* ORM编程思想(Object,relational,mapping)
* 表中的一条记录对应java类的一个对象
* 表中的字段对应java类的一个属性(数据类型)
*/
public class User {
private int id;
private String username;
private String password;
public User() {
}
public User(int id, String username, String password) {//带参构造器
this.id = id;
this.username = username;
this.password = password;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
查询ResultSet
package statement;
import jdbcUtil.JDBC_Util;
import org.junit.Test;
import user.User;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
/**
* Created by KingsLanding on 2022/6/5 17:16
*/
public class Select {
@Test
public void select() {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//获取链接
conn = JDBC_Util.getConnection();
//预编译
String sql="select * from user where id=?";
ps = conn.prepareStatement(sql);
ps.setInt(1,3);
//执行,并返回结果集
rs = ps.executeQuery();
//处理结果集
if(rs.next()){//判断结果是否有数据,有返回true 同时指针指向下一位
//获取当前这条数据的各个字段值
int id = rs.getInt(1);
String username = rs.getString(2);
String password = rs.getString(3);
//方式一:直接显示
//System.out.println("username"+username+"password"+password);
//方式二:存到数组里
//Object[] ob = {username, password};
//方式三:JavaBean,将要操作的数据封装成一个个对象
User user = new User(id, username, password);
System.out.println(user);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭资源
JDBC_Util.closeResource(conn,ps,rs);
}
}
}
查询通用
package statement;
import jdbcUtil.JDBC_Util;
import jdk.nashorn.internal.scripts.JD;
import org.junit.Test;
import user.User;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
/**
* Created by KingsLanding on 2022/6/6 13:04
*/
public class Select{
public User select(String sql, Object ...args){
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JDBC_Util.getConnection();
ps = conn.prepareStatement(sql);
for (int i=0;i<args.length;i++){
ps.setObject(i+1,args[i]);
}
rs = ps.executeQuery();
//获取结果集的元数据
ResultSetMetaData rsmd = rs.getMetaData();
//通过ResultSetMetaData获取结果集中的列数
int columnCount = rsmd.getColumnCount();
if(rs.next()){
User user = new User();
//处理结果集一行数据中的每一列
for(int i=0;i<columnCount;i++){
//获取列值
Object columnValue = rs.getObject(i + 1);
//获取每个列的列名
String columnName = rsmd.getColumnName(i+1);
//给user对象指定的columnName属性,赋值为columnValue,通过反射
Field field = User.class.getDeclaredField(columnName);
field.setAccessible(true);
field.set(user,columnValue);
}
return user;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBC_Util.closeResource(conn,ps,rs);
}
return null;
}
@Test
public void selectTest(){
String sql="select * from user where id=?";
User user1 = select(sql, 3);
System.out.println(user1);
}
}
查询获取列名——>获取别名
- 使用getColumnLabel替换getColumnName来获取列的别名
//获取每个列的列名getColumnName
//getColumnName()方法要求表的字段名,必须与javaBean类中的属性名相同,不推荐使用
String columnName = rsmd.getColumnName(i+1);
//获取每个列的别名
//别名的命名必须与javaBean类的属性名相同
String columnLabel = rsmd.getColumnLabel(i + 1);
/**
* 针对表的字段名与类的属性名不同的情况
* 1.必须声明sql时,使用类的属性来命名字段的别名
* 2.使用ResultSetMetaData获取结果集的元数据,使用getColumnLabel替换getColumnName
* 获取列的别名
* 说明:如果sql声明中没有字段的别名(字段名与属性名相同)getColumnLabel
* 同样能获取列名
*/
@Test
public void selectTest2(){
String sql ="select id ID,username userName,password pwd from user where id=?";
select(sql,3);
}
集合 不同数据表的通用查询
//创建集合对象 ArrayList list = new ArrayList<>();
package statement;
import jdbcUtil.JDBC_Util;
import org.junit.Test;
import user.Car;
import user.User;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
/**
* Created by KingsLanding on 2022/6/6 17:06
*/
public class List {
public <T> ArrayList<T> getForList(Class<T> clazz, String sql, Object ...args){
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JDBC_Util.getConnection();
ps = conn.prepareStatement(sql);
for (int i=0;i<args.length;i++){
ps.setObject(i+1,args[i]);
}
rs = ps.executeQuery();
//获取结果集的元数据
ResultSetMetaData rsmd = rs.getMetaData();
//通过ResultSetMetaData获取结果集中的列数
int columnCount = rsmd.getColumnCount();
//创建集合对象
ArrayList<T> list = new ArrayList<>();
while (rs.next()){
T t = clazz.newInstance();
//处理结果集一行数据中的每一列;给t对象指定的属性赋值
for(int i=0;i<columnCount;i++){
//获取列值
Object columnValue = rs.getObject(i + 1);
//获取每个列的列名getColumnName
//getColumnName()方法要求表的字段名,必须与javaBean类中的属性名相同,不推荐使用
//String columnName = rsmd.getColumnName(i+1);
//获取每个列的别名
//别名的命名必须与javaBean类的属性名相同
String columnLabel = rsmd.getColumnLabel(i + 1);
//给user对象指定的columnName属性,赋值为columnValue,通过反射
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t,columnValue);
}
list.add(t);
}
return list;
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBC_Util.closeResource(conn,ps,rs);
}
return null;
}
@Test
public void selectTest(){
String sql="select * from user where id<?";
ArrayList<User> forList = getForList(User.class, sql, 6);
forList.forEach(System.out::println);
}
@Test
public void selectTest01(){
String sql="select * from car where id<?";
ArrayList<Car> forList = getForList(Car.class, sql, 5);
forList.forEach(System.out::println);
}
}
两种技术
- JDBC结果集的元数据:ResultSetMetaData
- 获取列数:getColumnCount()
- 获取列的别名:getColumnLabel()
- 通过反射,创建指定类的对象,获取指定的属性并赋值
事务
-
数据库事务定义:
1.一组逻辑操作单元,使数据从一种状态变换到另一种状态
2.一组逻辑操作单元:一个或多个DML操作:增删改查(insert,delect,update,select)
-
事务处理的原则:保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。
就是说当一个事务中在执行多个操作时,要么所有操作都被提交,这些数据都将永久保存下来;要么数据库管理系统放弃所做的一切修改,整个事务回滚(rollback)最初状态。
-
数据一旦提交,就将不能在回滚,意味着回滚必须在事务提交之前,一旦连接关闭,当前事务就会直接提交,所以回滚也必须在数据库链接关闭之前
-
那些操作会导致数据的自动提交?
1.DDL操作一旦执行,都会自动提交:set autocommit = false 对DDL操作失效
2.DML默认情况下,一旦执行,就会自动提交:可以通过set autocommit = false的方式取消DML的自动提交
-
默认关闭连接是,会自动提交数据
考虑事务
- 调用 Connection 对象的 setAutoCommit(false); 以取消自动提交事务
- 在所有的 SQL 语句都成功执行后,调用 commit(); 方法提交事务
- 在出现异常时,调用 rollback(); 方法回滚事务
package test;
import jdbcUtil.JDBC_Util;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* Created by KingsLanding on 2022/6/8 12:30
*/
public class UpdateTure {
public static void main(String[] args) {
Connection conn=null;
try {
//1.在此处连接数据库
conn = JDBC_Util.getConnection();
//2.取消数据的自动提交
conn.setAutoCommit(false);
String sql="update user set username = ?,password = ? where id=3";
update(conn,sql,"张二","1234567");
// System.out.println(10/0);//模拟故障
String sql2="update user set username = ?,password = ? where id=4";
update(conn,sql2,"张万","12344556");
//3.完成提交数据
conn.commit();
System.out.println("转账成功");
} catch (Exception e) {
e.printStackTrace();
//4.数据回滚
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
} finally {
JDBC_Util.closeResource(conn,null);
}
}
//可变形参...arg必须和sql中的占位符对应
public static int update(Connection conn,String sql, Object... args) {
PreparedStatement ps = null;
try {
//数据库链接,造的地方链接
//2.预编译sql语句,返回PreparedStatement实例
ps = conn.prepareStatement(sql);
//3.填充占位符
for (int i = 0; i < args.length; i++) {
//i+1是占位符位置,从1开始,args[i]是数据库属性名从0开始
ps.setObject(i + 1, args[i]);
}
//4.执行
/**
* ps.execute()
* 如果执行的是查询操作,则返回true
* 如果执行的是增删改操作,则返回false
*/
// ps.execute();
return ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
//5.资源关闭
JDBC_Util.closeResource(null, ps);
}
return 0;
}
}
事务的ACID属性
- 原子性(Atomicity) 原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
- 一致性(Consistency) 事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
- 隔离性(Isolation) 事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
- 持久性(Durability) 持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。
6.3.1 数据库的并发问题
- 对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致各种并发问题:
- 脏读: 对于两个事务 T1, T2, T1 读取了已经被 T2 更新但还没有被提交的字段。之后, 若 T2 回滚, T1读取的内容就是临时且无效的。
- 不可重复读: 对于两个事务T1, T2, T1 读取了一个字段, 然后 T2 更新了该字段。之后, T1再次读取同一个字段, 值就不同了。
- 幻读: 对于两个事务T1, T2, T1 从一个表中读取了一个字段, 然后 T2 在该表中插入了一些新的行。之后, 如果 T1 再次读取同一个表, 就会多出几行。
- 数据库事务的隔离性: 数据库系统必须具有隔离并发运行各个事务的能力, 使它们不会相互影响, 避免各种并发问题。
- 一个事务与其他事务隔离的程度称为隔离级别。数据库规定了多种事务隔离级别, 不同隔离级别对应不同的干扰程度, 隔离级别越高, 数据一致性就越好, 但并发性越弱。
四种隔离级别
-
数据库提供的4种事务隔离级别:
-
Oracle 支持的 2 种事务隔离级别:READ COMMITED, SERIALIZABLE。 Oracle 默认的事务隔离级别为: READ COMMITED 。
-
Mysql 支持 4 种事务隔离级别。Mysql 默认的事务隔离级别为: REPEATABLE READ。
在MySql中设置隔离级别
-
每启动一个 mysql 程序, 就会获得一个单独的数据库连接. 每个数据库连接都有一个全局变量 @@tx_isolation, 表示当前的事务隔离级别。
-
查看当前的隔离级别:
SELECT @@tx_isolation; 1 -
设置当前 mySQL 连接的隔离级别:
set transaction isolation level read committed; 1 -
设置数据库系统的全局的隔离级别:
set global transaction isolation level read committed; 1 -
补充操作:
创建mysql数据库用户:
create user tom identified by 'abc123'; 1授予权限
#授予通过网络方式登录的tom用户,对所有库所有表的全部权限,密码设为abc123. grant all privileges on *.* to tom@'%' identified by 'abc123'; #给tom用户使用本地命令行方式,授予atguigudb这个库下的所有表的插删改查的权限。 grant select,insert,delete,update on atguigudb.* to tom@localhost identified by 'abc123';
德鲁伊线程池
druid闸瓦包下载地址
properties配置文件
username=root
password=zmj.666.999
url=jdbc:mysql://localhost:3306/jdbctest?serverTimezone=UTC
driverClass=com.mysql.jdbc.Driver
建立链接
/**
* Created by KingsLanding on 2022/6/10 13:10
*/
public class Druid_JDBC {
@Test
public static Connection getDruidConnection() throws Exception{
Properties pros = new Properties();
//读取druid.properties配置文件
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
//使用反射动态获取连接
//InputStream is = DruidUtils.class.getClassLoader().getResourceAsStream("druid.properties");
//从流中加载数据
pros.load(is);
//创建数据库连接池
DataSource source = DruidDataSourceFactory.createDataSource(pros);
//获取链接
Connection conn = source.getConnection();
System.out.println(conn);
return conn;
}
}
DbUtils工具类
-
Apache-DBUtils简介
commons-dbutils是Apache组织提供的一个开源JDBC工具类库,它是对JDBC的简单封装,学习成本极 低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能。 -
API介绍:
org.apache.commons.dbutils .QueryRunner org.apache.commons.dbutils ResultSetHandler 工具类: org.apache.commons.dbutils.DbUtils
DBUtils闸瓦包下载地址
操作测试
插入数据测试
(正常操作需要使用try-catch-finally)
public class InsertTest {
@Test
public void Insert()throws Exception{
//获取连接
Connection conn = Druid_JDBC.getDruidConnection();
//DBUtils工具类中的QueryRunner()
QueryRunner runner = new QueryRunner();
String sql="insert into user(name,age,phone)value(?,?,?)";
//DBUtils中提供的update方法
int insertCount = runner.update(conn, sql, "zmj", 22, "122343235");
System.out.println("插入了"+insertCount+"条数据");
//JDBC_Util.closeResource(conn,null);
//closeQuietly()关闭连接
DbUtils.closeQuietly(conn);
}
}
查询操作测试
/**
* Created by KingsLanding on 2022/7/9 15:19
*/
public class SelectTest {
/*
测试查询
BeanHandler:是ResultSetHandler接口的实现类,用于封装表中的一条数据
*/
@Test
public void QueryTest() throws Exception{
Connection conn = Druid_JDBC.getDruidConnection();
QueryRunner runner = new QueryRunner();
String sql="select id,name,age,phone from user where id=?";
BeanHandler<userBean> handler = new BeanHandler<>(userBean.class);
userBean query = runner.query(conn, sql, handler, 1);
System.out.println(query);
DbUtils.closeQuietly(conn);
}
/*
BeanListHandler 是ResultSetHandler<List<T>>接口的实现类,用于封装表中的多组数据
*/
@Test
public void selectTest2() throws Exception{
Connection conn = Druid_JDBC.getDruidConnection();
QueryRunner runner = new QueryRunner();
String sql="select id,name,age,phone from user where id<=?";
BeanListHandler<userBean> listHandler = new BeanListHandler<>(userBean.class);
List<userBean> query = runner.query(conn, sql, listHandler, 3);
// System.out.println(query);
//使用增强for循环遍历数据
// for (Object obj:query){
// System.out.println(obj);
// }
//使用迭代器遍历数据
Iterator<userBean> iterator = query.iterator();
while (iterator.hasNext()){
userBean next = iterator.next();
System.out.println(next);
}
DbUtils.closeQuietly(conn);
}
/*
MapHandler:是ResultSetHandler接口的实现类,对应表中的一条数据
将字段及相应的字段的值作为map中的key和value
*/
@Test
public void selectTest3()throws Exception{
Connection conn = Druid_JDBC.getDruidConnection();
QueryRunner runner = new QueryRunner();
String sql="select id,name,age,phone from user where id=?";
MapHandler mapHandler = new MapHandler();
Map<String, Object> query = runner.query(conn, sql, mapHandler, 3);
System.out.println(query);
DbUtils.closeQuietly(conn);
}
/*
查询特殊数据的操作ScalarHandler()
*/
@Test
public void test4() throws Exception{
Connection conn = Druid_JDBC.getDruidConnection();
QueryRunner runner = new QueryRunner();
String sql="select count(*) from user";
ScalarHandler scalarHandler = new ScalarHandler();
Long query = (Long) runner.query(conn, sql, scalarHandler);
System.out.println(query);
DbUtils.closeQuietly(conn);
}
@Test
public void test5() throws Exception{
Connection conn = Druid_JDBC.getDruidConnection();
QueryRunner runner = new QueryRunner();
String sql="select Max(age) from user";
ScalarHandler scalarHandler = new ScalarHandler();
Integer query =(Integer) runner.query(conn, sql, scalarHandler);
System.out.println(query);
DbUtils.closeQuietly(conn);
}
}