JDBC简介、JDBC程序编写步骤、JDBC工具类编写、数据库连接池、JDBC管理事务、commons-dbutils工具类库使用、JDBC批处理机制、单元测试
-
- 一、JDBC(Java Database Connectivity)简介
- 1.JDBC:java连接数据库的规范(标准),可以使用java语言连接各种不同的关系型数据库,并完成CRUD操作
- 2.JDBC的本质
- 3.JDBC常用API
- 1)java.sql.Driver 驱动接口
- 2)java.sql.DriverManager 驱动管理类(管理jdbc驱动服务)
- 3)java.sql.Connection 数据库连接接口
- 4)java.sql.Statement 数据库静态sql执行接口
- 5)java.sql.PreparedStatement (继承了Statement接口) 数据库预编译执行接口
- 6)java.sql.ResultSet 接收数据库查询结果集接口
- 7)javax.sql.DataSource 数据源接口
- 8)com.alibaba.druid.pool.DruidDataSourceFactory 德鲁伊数据源工厂类
- 9) org.apache.commons.dbutils.QueryRunner 查询执行类(里面封装了PreparedStatement,Connection以及释放资源的方法)
- 10)ResultSetHandler接口的实现子类
- 二、JDBC程序编写步骤
-
- 三、使用DriverManger类或者Driver类
-
- 四、数据库连接池
-
- 五、JDBC 编写工具类(连接池)
-
- 六、JDBC管理事务
- 七、commons-dbutils工具类库以及使用
- 八、JDBC批处理
-
- 九、单元测试
-
- 九、常见错误
-
- 与poppy一起学习
JDBC简介、JDBC程序编写步骤、JDBC工具类编写、数据库连接池、JDBC管理事务、commons-dbutils工具类库使用、JDBC批处理机制、单元测试
- 一、JDBC(Java Database Connectivity)简介
- 1.JDBC:java连接数据库的规范(标准),可以使用java语言连接各种不同的关系型数据库,并完成CRUD操作
- 2.JDBC的本质
- 3.JDBC常用API
- 1)java.sql.Driver 驱动接口
- 2)java.sql.DriverManager 驱动管理类(管理jdbc驱动服务)
- 3)java.sql.Connection 数据库连接接口
- 4)java.sql.Statement 数据库静态sql执行接口
- 5)java.sql.PreparedStatement (继承了Statement接口) 数据库预编译执行接口
- 6)java.sql.ResultSet 接收数据库查询结果集接口
- 7)javax.sql.DataSource 数据源接口
- 8)com.alibaba.druid.pool.DruidDataSourceFactory 德鲁伊数据源工厂类
- 9) org.apache.commons.dbutils.QueryRunner 查询执行类(里面封装了PreparedStatement,Connection以及释放资源的方法)
- 10)ResultSetHandler接口的实现子类
- 二、JDBC程序编写步骤
- 三、使用DriverManger类或者Driver类
- 四、数据库连接池
- 五、JDBC 编写工具类(连接池)
- 六、JDBC管理事务
- 七、commons-dbutils工具类库以及使用
- 八、JDBC批处理
- 九、单元测试
- 九、常见错误
- 与poppy一起学习
一、JDBC(Java Database Connectivity)简介
1.JDBC:java连接数据库的规范(标准),可以使用java语言连接各种不同的关系型数据库,并完成CRUD操作
2.JDBC的本质
JDBC的本质是一个java类,实现了sun公司规定的“数据库应用程序接口规范”,该类也称为jar包或数据库驱动,由不同的数据库厂商提供,通过该jar包或者数据库驱动,才能访问不同的关系型数据库,并对其数据进行CRUD操作
3.JDBC常用API
1)java.sql.Driver 驱动接口
有一个Driver类实现了Driver接口
普通方法:
1>驱动对象.connect(String url,Properties properties); 返回连接对象
2>静态代码块. 用于类加载时注册驱动
public class Driver implements java.sql.Driver{
static{
try{
java.sql.DriverManager.registerDriver(new Driver());
}catch(SQLException E){
throw new RuntimeException("Cant't register driver!");
}
}
}
2)java.sql.DriverManager 驱动管理类(管理jdbc驱动服务)
静态方法:
1>DriverManager.registerDriver(Driver driver); 用于注册驱动
2>DriverManager.getConnection(String url,String username, String possword); 用于返回连接对象
url:统一资源定位符-(由协议、IP、端口、库名组成)
例. jdbc:mysql://localhost:3306:数据库名
username:数据库用户名
possword:数据库登陆密码
3)java.sql.Connection 数据库连接接口
普通方法
1>连接对象名.createStatement(); 返回Statement执行对象
2>连接对象名.prepareStatement(String sql); 返回PreparedStatement预编译对象,并将参数化的sql语法发送给数据库编译后,存储到预编译对象中
参数化sql:字段的值没有给定,使用?(占位符或参数标记),后续通过预编译对象的set方法设定值
例:insert into 表名 values(?,?...);
3>连接对象名.setAutoCommit(); 设定事务提交方式(false为手动提交)
4>连接对象名.rollback(); 回滚事物
5>连接对象名.commit(); 提交事物
4)java.sql.Statement 数据库静态sql执行接口
普通方法
1>执行对象名.executeUpdate(String sql); 返回int型的受影响的行数
用于对数据库DML或者DDL(表)的操作
2>执行对象名.executeQuery(String sql); 返回ResultSet查询结果集的对象
用于对数据库DQL的操作
3>执行对象名.execute(sql); 执行任意sql语句,返回boolean值
静态sql语句:直接写定的sql语句
例:insert into 表名 values(值1,值2...);
5)java.sql.PreparedStatement (继承了Statement接口) 数据库预编译执行接口
普通方法
1>预编译对象名.set字段类型(index,values); 给占位符第index位,设定values值
2>预编译对象名.setObject(index,values);
3>预编译对象名.executeUpdate(); 返回int型的受影响的行数
用于对数据库DML或者DDL(表)的操作
4>预编译对象名.executeQuery(String sql); 返回ResultSet查询结果集对象
用于对数据库DQL的操作
5>预编译对象名.execute(sql); 执行任意sql语句,返回boolean值
6>预编译对象名.addBatch(); 添加需要批处理的sql语句或参数
7>预编译对象名.executeBatch(); 执行批量处理语句
8>预编译对象名.clearBatch(); 清空批处理包的语句
6)java.sql.ResultSet 接收数据库查询结果集接口
普通方法
1>结果集对象名.next(); 返回boolean值,用于判断是否有下一行记录,如有,光标下移一行,如没有,返回false
2>结果集对象名.first(); 用于将光标移动到第一行
3>结果集对象名.previous(); 返回boolean值,用于判断是否有上一行记录,如有,光标上移一行,如没有,返回false
4>结果集对象名.get字段类型(index或者字段名); 用于获取指定索引或者字段的值,接收类型时字段类型对应的java类型
5>结果集对象名.getObject(index或字段名); 用于获取指定索引或者字段的值,接收类型是Object
7)javax.sql.DataSource 数据源接口
普通方法:
1>数据源对象名.getConnection(); 返回连接对象
8)com.alibaba.druid.pool.DruidDataSourceFactory 德鲁伊数据源工厂类
com.alibaba.druid.pool.DruidDataSource实现了javax.sql.DataSource接口
静态方法:
1>DruidDDataSourceFactory.createDataSource(Properties properties); 返回数据源对象
9) org.apache.commons.dbutils.QueryRunner 查询执行类(里面封装了PreparedStatement,Connection以及释放资源的方法)
普通方法:
1>对象名.query(String sql,ResultSetHandler rsh , Object ...param); 依据rsh不同实现子类,返回对应类型结果
2>对象名.query(Connection conn,String sql,ResultSetHandler rsh, Object ...param);可以加入事务(默认自动提交,通过该方法加入事务)
3>对象名.Update(String sql , Object...param)
4>对象名.Update(Connection conn,String sql,Object ...param);可以加入事务(默认自动提交,通过该方法加入事务)
10)ResultSetHandler接口的实现子类
ArrayHandler
ArrayListHandler
BeanHandler:可以将查询到结果集中的记录封装到一个java实体类中
实体类类名 对象名 =new BeanHandler<实体类名>(实体类的字节码文件);
BeanListHandler:可以将查询的多条记录封装到list集合中
List<实体类名> list = new BeanListHandler<实体类名>(实体类的字节码文件);
BearnMapHandler:可以将查询的多条记录封装到Map中
ScalarHandler:查询单行单列的数据(例聚合函数中查询总记录数)
Object obj = new ScalarHandler<>();
String s = String.valueOf(obj);
int counts =Integer.parseInt(s);
二、JDBC程序编写步骤
1.使用DriverManger类或者Driver类获取连接对象方式(7大步骤)
1)导包并注册驱动--加载Driver类
2)获得客户端或java程序的数据库连接--得到Connection
3)编写静态或者参数化sql语句
4)获得执行对象或者预编译对象
5)执行sql语句(DDL、DML、DQL)
6)返回结果
7)释放资源--先开后关
2.使用数据库池
1)导包并配置好数据库连接池的配置文件
2)读取配置文件并获得数据源对象(数据库连接池对象)
3)获取数据库的连接对象
4) 编写sql语句
5)获得执行对象或者预编译对象
6)执行sql语句(DDL、DML、DQL)
7)返回执行结果
8)释放资源--先开后关
3.使用commons-dbutils(工具类库)
1)导包
2) 获取数据源对象
3)获取QueryRunner对象并传入数据源对象
4)准备sql语句
5)执行sql语句
6)返回结果
(该工具类库中封装了PreparedStatement、Connection以及资源的释放)
三、使用DriverManger类或者Driver类
1.Driver
package com.hua.Test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.util.Properties;
public class TestDriver {
public static void main(String[] args) throws Exception {
//第一步:导包并注册驱动(以下两种方式都可以)
Driver driver = new com.mysql.jdbc.Driver();
// Class<?> cls = Class.forName("com.mysql.jdbc.Driver");
// Driver driver1 =(Driver) cls.newInstance();
Properties prop = new Properties();
prop.load(new FileInputStream("src//driver.properties"));
//第二步:获取连接对象
Connection conn = driver.connect("jdbc:mysql://localhost:3306/myee_2202", prop);
//第三步:准备静态sql
String sql1 = "update emp01 set name = 'lin' where id = 1"; //静态sql
// 第四步:获取执行对象
Statement statement = conn.createStatement();//执行对象
//第五步:执行sql语句并返回结果
int i1 = statement.executeUpdate(sql1);
System.out.println(i1==1 ? "成功":"失败" );
//第三步:准备动态sql
String sql2 = "update emp01 set name = ? where id =? ";//动态sql
//第四步:获取预编译对象
PreparedStatement ps = conn.prepareStatement(sql2);//预编译对象
ps.setString(1,"scalar");
ps.setInt(2,3);
//第五步:执行sql并返回结果
int i2 = ps.executeUpdate();
System.out.println(i2==1 ? "成功":"失败" );
//第六步:释放资源
ps.close();
statement.close();
conn.close();
}
}
2. DriverManager
package com.hua.Test;
import java.io.FileInputStream;
import java.sql.*;
import java.util.Properties;
public class TestDriver {
public static void main(String[] args) throws Exception {
//第一步:导包并注册驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Properties prop = new Properties();
prop.load(new FileInputStream("src//driver.properties"));
//第二步:获取连接对象
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/myee_2202", prop);
//第三步:准备静态sql
String sql1 = "update emp01 set name = 'abby' where id = 1"; //静态sql
// 第四步:获取执行对象
Statement statement = conn.createStatement();//执行对象
//第五步:执行sql语句并返回结果
int i1 = statement.executeUpdate(sql1);
System.out.println(i1==1 ? "成功":"失败" );
//第三步:准备动态sql
String sql2 = "update emp01 set name = ? where id =? ";//动态sql
//第四步:获取预编译对象
PreparedStatement ps = conn.prepareStatement(sql2);//预编译对象
ps.setString(1,"demon");
ps.setInt(2,3);
//第五步:执行sql并返回结果
int i2 = ps.executeUpdate();
System.out.println(i2==1 ? "成功":"失败" );
//第六步:释放资源
ps.close();
statement.close();
conn.close();
}
}
3.Statement 与 PreparedStatement的区别
1>执行效率
Statement 只能执行静态sql语句,每执行一条,都需要单独发给数据库编译,效率低
PreparedStatement可以通过参数化sql语句,动态填充数据,同构造的sql语句只需在获取预编译对象时发送给数据库编译一次,编译后的sql会储存到预编译对象中,后续通过预编译对象的set方法设定不同的值,执行效率高
2>sql注入
Statement的sql语句是字符串拼接而成,而且是在用户输入数据,整合后发给数据库编译,如果用户输入的数据中包含关键字或者语法,会导致sql注入问题
PreparedStatement的sql语句是在获取预编译对象时发送给数据库编译,在用户输入数据前已编译好完整的sql语句,此时即便用户输入SQL关键字或者语法也不会影响已编译的sql语句,有效避免了SQL注入
提示:
1.mysql驱动5.1.6及以后可以无需写Class.forName(“com.mysql.jdbc.Driver”);
2.从jdk1.5以后使用了jdbc4,就不需要显示的调用class.forName()注册驱动而是自动调用驱动jar包下的META-INF\services\java.sql.Driver文本中的类名称去注册
四、数据库连接池
1.简介
1)Jdbc的数据库连接池使用javax.sql.DataSource表示,DataSourc只是一个接口,通常由第三方提供实现
2)预先在缓冲池中放入一定数量的连接对象,当需要连接数据库时,从缓冲池中取出一个连接对象,使用完后归还
3)数据库连接池负责分配、管理、释放连接,它允许应用程序使用一个现有的连接,而不是重新建立一个
4)当应用程序向连接池请求的连接数超过最大数量时,这些请求将被加入到等待队列
2.传统获取Connection的问题分析
1)传统的JDBC数据库连接是通过DriverManger类的静态方法获取,每次向数据库建立连接,都要将Connection加载到内存中,再验证IP地址、用户名、密码(约耗时0.05~1s),如频繁的进行数据库连接操作会占用很多系统资源,容易造成服务器奔溃
2)每一次数据库连接,使用完后都得断开,如果程序出现异常而未能关闭,将导致数据库内存泄漏 ,最终将导致重启数据库
3)传统获取连接的方式,不能控制连接数量,如果连接过多,也会导致内存泄漏,Mysql崩溃
3.数据库连接池的种类
1)C3P0数据库连接池:速度相对较慢,稳定性不错(hibernate,spring中有使用)
2)DBCP数据库连接池:速度相对C3P0较快,但不稳定
3)Proxool数据库连接池:有监控连接池状态的功能,稳定性较C3P0差一点
4)BoneCP数据库连接池:速度快
5)Druid(德鲁伊)数据库连接池:是阿里提供的,集C3P0、DBCP、Proxool优点于一身
传统方式连接数量较多,崩溃的代码演示
package com.hua.Test;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
public class SqlBreakdowm {
public static void main(String[] args) {
Properties properties = new Properties();
try {
properties.load(new FileInputStream("src//Jdbc01.properties"));
String url = properties.getProperty("url");
String user = properties.getProperty("user");
String password = properties.getProperty("password");
for (int i = 0; i <= 5000; i++) {
Connection conn = DriverManager.getConnection(url,user,password);
System.out.println("连接第" + i + "次");
}
} catch (IOException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
运行结果:
连接第1次~第103次
com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source rejected establishment of connection, message from server: "Too many connections"
4.C3P0数据库连接池的使用
步骤:
1)导包
2)获得数据源对象
3)
第一种方式,在程序中设置参数
//获取数据源对象
ComboPooledDataSource cpds = new ComboPooledDataSource();
//通过配置文件获取相关信息
Properties prop = new Properties();
prop.load(new FileInputStream("src//Jdbc.properties"));
String url = prop.getProperty("url");
String username = prop.getProperty("username");
String password = prop.getProperty("password");
String driverpath = prop.getProperty("driverpath");
//给数据源设置相关的参数
cpds.setDriverClass(driverpath);
cpds.setJdbcUrl(url);
cpds.setUser(username);
cpds.setPassword(password);
//初始化连接数
cpds.setInitialPoolSize(10);
//最大连接数
cpds.maxPoolSize(50);
//获取连接对象
Connection conn = cpds.getConnection();
第二种方式,使用C3P0提供的配置文件
//将C3P0提供的c3p0.config.xml拷贝到src目录下(该文件指定了连接数据库和连接池的相关参数)
//在c3p0.config.xml文件中设置参数
//获取数据源对象
ComboPooledDataSource cpds = new ComboPooledDataSource(“数据源名称”);
//获取连接对象
Connection conn = cpds.getConnection();
5.Druid数据库连接池的使用
package com.hua.Test;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
public class DruidSqlPool {
public static void main(String[] args) {
// 第一步导包(druid-1.1.10.jar)并配置好数据库连接池中的文件
/*
注意:配置文件中的key按DruidDataSource中的参数写,不能随意自定义,不然读取不到
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/myee_2202
username=root
password=123456
initialSize=10 //初始化连接数量
maxActive=10 //最大激活数量
minIdle=4 //最小空闲数量
maxwait=3000 //最大等待时间
*/
//第二步:读取配置文件并获取数据源对象
Properties prop = new Properties();
ResultSet rs = null;
PreparedStatement ps = null;
Connection conn = null;
try {
prop.load(new FileInputStream("src//druid.properties"));
DataSource ds = DruidDataSourceFactory.createDataSource(prop);
//第三步:获取连接对象
conn = ds.getConnection();
//第四步:编写sql语句
String sql = "select * from emp01 where id = ?";
//第五步:获取预编译对象,并将sql语句发送数据库编译
ps = conn.prepareStatement(sql);
ps.setInt(1,3);
//第六步:执行sql
rs = ps.executeQuery();
//第七步:返回结果
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
String gender = rs.getString("gender");
String address = rs.getString("address");
int salary = rs.getInt("salary");
System.out.println(id + "\t" + name + "\t" + age + "\t" + gender + "\t" + address + "\t" + salary);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (rs == null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (ps == null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn == null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
运行结果:
五月 21, 2022 3:46:10 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
3 fiona 25 female poland 25000
五、JDBC 编写工具类(连接池)
1.步骤
1)定义属性,并私有化构造函数
2)静态代码块用于注册驱动、读取配置文件并初始化属性
3)定义一个静态方法用于提供数据源对象
4)定义一个静态方法用于提供连接对象
5)定义方法用于释放资源
注意:由于每个线程都有自己的连接对象,需要先判断当前线程有没有连接对象,如有,直接获取,如没有再从连接池获取并绑定到当前线程,资源释放后,需要解绑连接对象!!
2.示例代码
package com.hua.Test;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
public class TestJdbcUtils {
//第一步:定义属性,私有化构造函数
private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
private static DataSource ds;
private TestJdbcUtils() {
}
//第二步:静态代码块用于读取配置文件,并创建数据源对象
static{
//读取配置文件(以下两种方式都可以获得输入流,任选一个)
Properties prop = new Properties();
try {
prop.load(new FileInputStream("src//druid.properties"));
//prop.load(TestJdbcUtils.class.getClass().getResourceAsStream("druid.properties"));
//获取数据源对象
ds = DruidDataSourceFactory.createDataSource(prop);
} catch (Exception e) {
e.printStackTrace();
}
}
//第三步:定义一个静态方法用于提供数据源对象
public static DataSource getDataSourceObject(){
return ds;
}
//第四步:定义一个静态方法用于提供连接对象
public static Connection getConnectionObject() throws SQLException {
//先判断当前线程中是带有连接
Connection conn = tl.get();
if (conn == null) {
conn = ds.getConnection();
//此次注意将连接对象绑定给当前线程
tl.set(conn);
}
return conn;
}
//第五步:定义静态方法用于释放资源
public static void close(PreparedStatement ps, Connection conn){
closeAll(null,ps,conn);
}
public static void closeAll(ResultSet rs, PreparedStatement ps, Connection conn){
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
//此处注意解绑当前线程的连接对象
tl.remove();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//使用main方法测试工具类是否可以正常使用
public static void main(String[] args) {
for (int i = 0; i <=200 ; i++) {
try {
Connection conn = TestJdbcUtils.getConnectionObject();
System.out.println("连接了" + i + "次"+conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
运行结果:
五月 21, 2022 4:20:03 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
连接了0次com.mysql.jdbc.JDBC4Connection@233c0b17
连接了1次com.mysql.jdbc.JDBC4Connection@63d4e2ba
连接了2次com.mysql.jdbc.JDBC4Connection@7bb11784
连接了3次com.mysql.jdbc.JDBC4Connection@33a10788
连接了4次com.mysql.jdbc.JDBC4Connection@7006c658
连接了5次com.mysql.jdbc.JDBC4Connection@34033bd0
连接了6次com.mysql.jdbc.JDBC4Connection@47fd17e3
连接了7次com.mysql.jdbc.JDBC4Connection@7cdbc5d3
连接了8次com.mysql.jdbc.JDBC4Connection@3aa9e816
连接了9次com.mysql.jdbc.JDBC4Connection@17d99928
//解释:由于最大激活数量限定了10,所以只分配了10个连接对象
六、JDBC管理事务
package com.hua.Test;
import org.apache.commons.dbutils.QueryRunner;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class TestCommit {
public static void main(String[] args) {
DataSource ds = TestJdbcUtils.getDataSourceObject();
Connection conn = null;
try {
conn = TestJdbcUtils.getConnectionObject();
//设置为手动提交
conn.setAutoCommit(false);
QueryRunner qr = new QueryRunner(ds);
String sql1 = "update account set balance = balance + 800 where id = 1 ";
String sql2="update account set balance = balance - 800 where id = 2 ";
qr.update(conn,sql1);
//int i =10/0;
qr.update(conn,sql2);
//全部执行完毕时提交事务
conn.commit();
} catch (Exception e) {
e.printStackTrace();
try {
//有异常时自动回滚
conn.rollback();
System.out.println("事务已回滚");
} catch (SQLException ex) {
ex.printStackTrace();
}
}
}
}
七、commons-dbutils工具类库以及使用
1.dbutils是Apache组织机构旗下的开源工具类库
2.针对原生jdbc进行了封装,简化了jdbc操作
3.API参考以上(9,10)
package com.hua.Test;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.hua.pojo.Emp01;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.List;
public class TestCommonsDbutils {
public static void main(String[] args) {
//第一步:导包(commons-dbutils核心包与依赖包)
//第二步:获取数据源对象(使用自己封装的工具类)
DataSource ds = TestJdbcUtils.getDataSourceObject();
//第二步:获取QueryRunner对象
QueryRunner qr = new QueryRunner(ds);
//编写sql语句
String sql = "select * from emp01";
//执行sql语句,并将记录存放到List集合中
List<Emp01> list = null;
try {
list = qr.query(sql, new BeanListHandler<Emp01>(Emp01.class));
} catch (SQLException e) {
e.printStackTrace();
}
for (Emp01 emp01 : list) {
System.out.println(emp01);
}
}
}
package com.hua.Test;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.hua.pojo.Emp01;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.List;
public class TestCommonsDbutils {
public static void main(String[] args) {
//第一步:导包(commons-dbutils核心包与依赖包)
//第二步:获取数据源对象(使用自己封装的工具类)
DataSource ds = TestJdbcUtils.getDataSourceObject();
//第二步:获取QueryRunner对象
QueryRunner qr = new QueryRunner(ds);
//编写sql语句
String sql = "select * from emp01 where id = ?";
//执行sql语句,并将记录存放到实体类对象中
Emp01 emp01 = null;
try {
emp01 = qr.query(sql, new BeanHandler<Emp01>(Emp01.class), 2);
System.out.println(emp01 );
} catch (SQLException e) {
e.printStackTrace();
}
}
}
运行结果:
五月 21, 2022 5:08:44 下午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
Emp01{id=2, name='tom', age=21, gender='male', address='england', salary=15000}
八、JDBC批处理
1.当需要成批插入或者更新记录时,可以采用java的批量处理机制,往往和PreparedStatement搭配使用,既可以减少编译次数,有减少运行次数,效率大大提高
2.相关方法API请参考常用API中第五点
3.注意:使用批处理时,必须在url中加参数?rewriteBatchedStatements=true ,如果没有添加该参数,使用批处理方法无效
4.示例代码如下
1)单独处理批量数据
package com.hua.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
public class TestNoBatch {
public static void main(String[] args) throws Exception {
Connection conn = TestJdbcUtils.getConnectionObject();
String sql = "insert into account values(null, ?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
long start = System.currentTimeMillis();
for (int i = 1; i <=5000 ; i++) {
ps.setString(1,"jack"+i);
ps.setInt(2,(1000+i));
ps.executeUpdate();
}
long end = System.currentTimeMillis();
System.out.println("单独插入批量数据耗时" + (end - start));
}
}
运行结果:
五月 22, 2022 10:49:57 上午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
单独插入批量数据耗时1907
2)使用批处理机制处理批量数据
package com.hua.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
public class TestNoBatch {
public static void main(String[] args) throws Exception {
Connection conn = TestJdbcUtils.getConnectionObject();
String sql = "insert into account values(null, ?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
long start = System.currentTimeMillis();
for (int i = 1; i <=5000 ; i++) {
ps.setString(1,"jack"+i);
ps.setInt(2,(1000+i));
//增加批处理机制
ps.addBatch();
if((i % 1000) == 0){
//执行批处理sql语句
ps.executeBatch();
//清空批处理包
ps.clearBatch();
}
}
long end = System.currentTimeMillis();
System.out.println("使用批处理机制插入批量数据耗时" + (end - start));
}
}
运行结果:
五月 22, 2022 10:57:46 上午 com.alibaba.druid.pool.DruidDataSource info
信息: {dataSource-1} inited
使用批处理机制插入批量数据耗时219
九、单元测试
1.单元测试分类
白盒测试:技术含量大于黑盒测试---测试开发方向
黑盒测试
2.操作步骤
1)导包(junit核心包以及hmrecrest-core依赖包)
2)编写单元测试方法(注意改方法没有返回值类型,没有参数,不能在构造函数私有的类中使用)
3)标记方法为单元测试,在方法上面加@Test注解
4)在junit包下一个断言Assert,来判断测试功能的结果
(如果测试自己的功能可以不用断言,可以直接接口多态测试数据是否存在)
九、常见错误
java.lang.ClassNotFoundException:找不到类
类名写错、没有导入jar包
java.sql.SQLException:与sql语句相关的错误
约束错误、表名、列名书写错误
建议:在客户端工具中测试sql语句之后再粘贴
com.mysql.jdbc.exception.jdbc4.MySQLSyntaxErrorException:Unknow column
列值String类型没有加单引号
Duplicate entry ‘1’ for key ‘PRIMARY’
主键值已存在或者混乱,更改主键值或者清空表
com.mysql.jdbc.exception.jdbc4.MySQLSyntaxErrorException:Unkonw column ‘password’ in
原因:可能输入的值的类型不对
与poppy一起学习
预习Servlet