mysql jdbc批处理_JDBC批处理 数据库连接池

关于JDBC

Jdbc是java database connectivity的简称,java数据库连接,专门用来通过一段java代码连接数据库的一门技术。

使用方法大致为一下六个步骤:

一、注册驱动

注册驱动有两种方式:

1.  Class.forName("com.mysql.jdbc.Driver");

这种方式不会对具体的驱动类产生依赖(即不用import驱动类)。Class类的forName方法中对参数指定的类进行了装载操作。在这里将com.mysql.jdbc.Driver类装载到jvm。众所周知,类装载时,将执行被装载类的静态代码块,而Driver类有一个静态代码块如下:

static{try{

java.sql.DriverManager.registerDriver(newDriver());

}catch(SQLExceptione){

thrownew RuntimeException("can't register driver!");

}

}

所以在装载过程中即完成了driver的注册。这也是使用最多的一种注册驱动方式。

2.    DriverManager.registerDriver(newcom.mysql.jdbc.Driver());

这种方式会造成DriverManager中产生两个一样的驱动,并会对具体的驱动类产生依赖。

具体来说就是:

1.    装载Driver类时注册一次驱动(有关类装载,请参考http://www.yanwushu.com/post/54.html),执行此代码时,又注册一次。

2.    由于实例化了com.mysql.jdbc.Driver.class,导致必须import该类,从而具体驱动产生了依赖。

3.    System.setProperty("jdbc.drivers","com.mysql.jdbc.Driver");

通过系统的属性设置注册驱动,如果要注册多个驱动,则System.setProperty("jdbc.drivers","com.mysql.jdbc.Driver:com.oracle.jdbc.Driver");

这种驱动注册方式很少使用。

二、获取数据库连接对象(java.sql.Connection)

Connection conn =DriverManager.getConnection("jdbc:mysql://localhost:3306/jtdb","root","root");

三、获取传输器

connection对象提供了两种传输器,Statement和PreparedStatement

两种传输器的区别与关系:

关系:PreparedStatement继承自Statement,都是接口

区别:PreparedStatement可以使用占位符,是预编译的,批处理比Statement效率高

四、执行sql语句,接收结果

如果是查询结果则用ResultSet 接收,如果是增删改的话,用int类型接收

如:

Statement st =(Statement) conn.createStatement();

String sql= "select * from at_school where owner ='"+user_id+"'";

ResultSet rs=st.executeQuery(sql);

sql= "UPDATE at_school SET state='1' WHERE id='"+id+"'";int rs2 = st.executeUpdate(sq);

五、遍历结果集(java.sql.ResultSet)

ResultSet对象维护指向结果集中当前行的游标。 术语“结果集”是指包含在ResultSet对象中的行和列数据。

ResultSet rs=st.executeQuery(sql);

ResultSet接口中有几种涉及移动光标的方法,其中常用的包括:public boolean next() throwsSQLException 将光标移动到下一行。 如果结果集中没有更多行,则此方法返回false。public boolean absolute(int row) throwsSQLException 将光标移动到指定的行。public void last() throwsSQLException 将光标移动到最后一行。while(rs.next()){//根据列的索引获取第一列的数据

String id = rs.getString(1);//根据列的索引获取第二列的数据

String username = rs.getString(2);//根据列的索引获取第三列的数据

String password = rs.getString(3);

}

六、释放资源

rs.close(); //释放结果集资源st.close();//释放传输器资源conn.close();//释放连接资源

demo

importjava.sql.Connection;importjava.sql.DriverManager;importjava.sql.ResultSet;importjava.sql.SQLException;importjava.sql.Statement;importorg.junit.Test;importcom.mysql.jdbc.Driver;public classHelloJDBC {//单元测试方法:@Test + void

@Testpublic voidhello() throwsSQLException{//1,注册驱动com.mysql.jdbc.Driver

DriverManager.registerDriver(newDriver());//2,获取数据库连接java.sql.Connection

Connection conn =DriverManager.getConnection("jdbc:mysql://localhost:3306/jtdb","root","root");//3,获取传输器java.sql.Statement

Statement st =conn.createStatement();//4,执行SQL。java.sql.ResultSet

String sql ="select * from user";

ResultSet rs=st.executeQuery(sql);//5,遍历结果集

while(rs.next()){//根据列的索引获取第一列的数据

String i = rs.getString(1);//根据列的索引获取第二列的数据

String username = rs.getString(2);//根据列的索引获取第三列的数据

String password = rs.getString(3);

System.out.println(id+username+password);

}//6,释放资源

rs.close();//释放结果集资源

st.close();//释放传输器资源

conn.close();//释放连接资源

}

}

JDBC工具类

importjava.sql.Connection;importjava.sql.DriverManager;importjava.sql.ResultSet;importjava.sql.SQLException;importjava.sql.Statement;importjava.util.ResourceBundle;/*** 这个类用来提供jdcb的工具类

* 构造方法私有化

* 该类提供一个getConnetion()方法,提供connection对象

* 提供close()方法,释放资源

*@authorwjx

**/

public classJDBCUtils {

​//私有化构造函数

privateJDBCUtils(){

}//加载配置文件

static ResourceBundle rb = null;//只加载一次属性文件

static{

rb= ResourceBundle.getBundle("jdbc");

}//提供一个数据库连接对象

public static Connection getConn() throwsClassNotFoundException {try{//注册驱动

Class.forName(rb.getString("driverClass"));//数据库名,所在地址和端口号

String url = rb.getString("jdbcUrl");//用户名

String user = rb.getString("user");//密码

String password = rb.getString("password");//获取数据库连接对象

Connection conn =DriverManager.getConnection(url, user, password);returnconn;

}catch(SQLException e) {//TODO Auto-generated catch block

e.printStackTrace();

}return null;

}public static voidclose(Connection conn,Statement st,ResultSet rs){//从结果集开始释放,依次是:ResultSet-->Statement-->Connection//非空判断,防止空指针异常

if(rs!=null){try{

rs.close();

}catch(SQLException e) {

e.printStackTrace();

}finally{

rs=null;//手动置空

}

}//释放传输器资源//非空判断,防止空指针异常

if(st!=null){try{

st.close();

}catch(SQLException e) {

e.printStackTrace();

}finally{

st=null;//手动置空

}

}//释放数据库连接资源//非空判断,防止空指针异常

if(conn!=null){try{

conn.close();

}catch(SQLException e) {

e.printStackTrace();

}finally{

conn=null;//手动置空

}

}

}public static voidclose(Connection conn,Statement st){//释放传输器资源//非空判断,防止空指针异常

if(st!=null){try{

st.close();

}catch(SQLException e) {

e.printStackTrace();

}finally{

st=null;//手动置空

}

}//释放数据库连接资源//非空判断,防止空指针异常

if(conn!=null){try{

conn.close();

}catch(SQLException e) {

e.printStackTrace();

}finally{

conn=null;//手动置空

}

}

}

}

配置文件(jdbc.properties)

driverClass=com.mysql.jdbc.Driver

jdbcUrl=jdbc:mysql:///test

user=root

password=123456

关于批处理

当我们需要向数据库中插入大量数据时,批处理会将这些数据打成多个批次addBatch(),统一发送给数据库服务器执行executeBatch(),减少与数据库的交互次数提高程序的执行效率。

如果有一个功能需求,是向数据库中插入50000条数据,这种需求如果不用批处理的话,会非常非常的耗时和资源。

不用批处理的情况下

用statement传输器

demo:

//不用批处理,Statement传输器下 用时: 1456秒

@Testpublic voidtest01(){try{//获取数据库连接

Connection conn =JDBCUtill.getConn();//创建传输器(Statement)

Statement st =conn.createStatement();//将开始插入的时间记录下来

Long begin =System.currentTimeMillis();//执行sql语句

for(int i = 1;i<50000;i++){

st.executeUpdate("insert into user (id,username,password) values ("+i+",'user "+i+"','paw "+i+"')");

}

System.out.println("用时: "+(System.currentTimeMillis()-begin)/1000+"秒");

st.close();

conn.close();

}catch(Exception e) {//TODO Auto-generated catch block

e.printStackTrace();

}

}

用PreparedStatement传输器

demo:

//不用批处理,PreparedStatement传输器下 用时: 1391秒

@Testpublic voidtest02(){try{//获取数据库连接

Connection conn =JDBCUtill.getConn();//创建传输器(PreparedStatement)

String sql ="insert into user (id,username,password) values (?,?,?)";

PreparedStatement pst=conn.prepareStatement(sql);//将开始插入的时间记录下来

Long begin =System.currentTimeMillis();//执行sql语句

for(int i = 1;i<50000;i++){

pst.setInt(1, i);

pst.setString(2, "username "+i);

pst.setString(3, "psw "+i);

pst.executeUpdate();

}

System.out.println("用时: "+(System.currentTimeMillis()-begin)/1000+"秒");

pst.close();

conn.close();

}catch(Exception e) {//TODO Auto-generated catch block

e.printStackTrace();

}

}

用批处理

JDBC实现批处理有两种方式:statement和preparedstatement

statement实现批处理:

demo:

//向test数据库中的user表中插入50000条数据//用批处理,Statement传输器下 用时: 12秒

@Testpublic void test05() throwsSQLException{try{

Connection conn=JDBCUtill.getConn();//将自动提交设为false

conn.setAutoCommit(false);//创建一个 PreparedStatement传输器

Statement st =conn.createStatement();//将开始插入的时间记录下来

Long begin =System.currentTimeMillis();//设置需要插入语句的总数和每一批提交的数量

int count = 50000;int batchsize = 5000;for(int i = 9 ; i < count;i++){//添加一条sql语句

String sql = "insert into user (id,username,password) values ('"+i+"','"+i+"','"+i+"')";

st.addBatch(sql);//每5000条为一批

if(i%batchsize==0){//执行一次批处理

st.executeBatch();//提交

conn.commit();

}

}//如果还有剩余,则再执行一次批处理

if ((count+1) % batchsize != 0) {

st.executeBatch();

conn.commit();

}

System.out.println("用时: "+(System.currentTimeMillis()-begin)/1000+"秒");

st.close();

conn.close();

}catch(ClassNotFoundException e) {//TODO Auto-generated catch block

e.printStackTrace();

}

}

采用Statement.addBatch(sql)方式实现批处理:

优点:可以向数据库发送多条不同的SQL语句。

缺点:SQL语句没有预编译。

当向数据库发送多条语句相同,但仅参数不同的SQL语句时,需重复写上很多条SQL语句。

preparedstatement实现批处理:

demo:

//用批处理,PreparedStatement传输器下(不加rewriteBatchedStatements=true 参数) 用时: 12秒

@Testpublic void test03() throwsSQLException {try{

Connection conn=JDBCUtill.getConn();//将自动提交设为false

conn.setAutoCommit(false);

String sql= "insert into user (id,username,password) values (?,?,?)";//创建一个 PreparedStatement传输器

PreparedStatement pst =conn.prepareStatement(sql);//将开始插入的时间记录下来

Long begin =System.currentTimeMillis();//设置需要插入语句的总数和每一批提交的数量

int count = 50000;int batchsize = 5000;for(int i = 1 ; i < count;i++){

pst.setLong(1, i);

pst.setString(2, "batch test"+i);

pst.setString(3, "test psw"+i);//添加一条sql语句

pst.addBatch();//每5000条为一批

if(i%batchsize==0){//执行一次批处理

pst.executeBatch();//提交

conn.commit();

}

}//如果还有剩余,则再执行一次批处理

if ((count+1) % batchsize != 0) {

pst.executeBatch();

conn.commit();

}

System.out.println("用时: "+(System.currentTimeMillis()-begin)/1000+"秒");

pst.close();

conn.close();

}catch(ClassNotFoundException e) {//TODO Auto-generated catch block

e.printStackTrace();

}

}

采用PreparedStatement.addBatch()实现批处理

优点:发送的是预编译后的SQL语句,执行效率高。

缺点:只能应用在SQL语句相同,但参数不同的批处理中。因此此种形式的批处理经常用于在同一个表中批量插入数据,或批量更新表的数据。

如果数据库连接对象没有设置rewriteBatchedStatements=true参数的话,效率会低一些

demo:

//用批处理,PreparedStatement传输器下(加上rewriteBatchedStatements=true 参数) 用时: 2秒

@Testpublic void test04() throwsSQLException {try{

Connection conn=JDBCUtill.getConn_batch();//将自动提交设为false

conn.setAutoCommit(false);

String sql= "insert into user (id,username,password) values (?,?,?)";//创建一个 PreparedStatement传输器

PreparedStatement pst =conn.prepareStatement(sql);//将开始插入的时间记录下来

Long begin =System.currentTimeMillis();//设置需要插入语句的总数和每一批提交的数量

int count = 50000;int batchsize = 5000;for(int i = 1 ; i < count;i++){

pst.setLong(1, i);

pst.setString(2, "batch test"+i);

pst.setString(3, "test psw"+i);//添加一条sql语句

pst.addBatch();//每5000条为一批

if(i%batchsize==0){//执行一次批处理

pst.executeBatch();//提交

conn.commit();

}

}//如果还有剩余,则再执行一次批处理

if ((count+1) % batchsize != 0) {

pst.executeBatch();

conn.commit();

}

System.out.println("用时: "+(System.currentTimeMillis()-begin)/1000+"秒");

pst.close();

conn.close();

}catch(ClassNotFoundException e) {//TODO Auto-generated catch block

e.printStackTrace();

}

}

关于数据库连接池

什么是数据库连接池?

用来存放数据库连接的一个容器,这个容器在整个程序中共享。提高程序的执行效率降低与数据库的交互次数。

主要有两个优点:实现数据库连接对象的复用,降低与数据库的交互次数。

自定义一个简易的数据库连接池

主要有以下几个步骤:

1、创建pool类,继承自DataSource

2、创建容器,用来存放数据库连接对象(LinkedList)

3、在静态代码块中完成容器初始化

4、提供getConnection方法,对外提供获取数据库连接对象(Connection)的方法

5、提供returnConnection方法,用来把用了的数据库连接对象放回池中。

demo:

importjava.io.PrintWriter;importjava.sql.Connection;importjava.sql.SQLException;importjava.sql.SQLFeatureNotSupportedException;importjava.util.LinkedList;importjava.util.List;importjava.util.logging.Logger;importjdbc.JDBCUtill;

​importjavax.sql.DataSource;

​/*** 自定义一个数据库连接池

* 步骤:

* 1、创建pool类,继承自DataSource

* 2、创建容器,用来存放数据库连接对象(LinkedList)

* 3、在静态代码块中完成容器初始化

* 4、提供getConnection方法,对外提供获取数据库连接对象(Connection)的方法

* 5、提供returnConnection方法,用来把用了的数据库连接对象放回池中。

*@authorwjx

**/​public class Pool implementsDataSource{

​static int total = 5;//创建容器,用来存放数据库连接对象(LinkedList)

static List pool = new LinkedList();//在静态代码块中完成容器初始化

static{for(int i = 0; i < total;i++){try{

Connection conn=JDBCUtill.getConn();

pool.add(conn);

}catch(ClassNotFoundException e) {

e.printStackTrace();

}

}

}//提供getConnection方法,对外提供获取数据库连接对象(Connection)的方法

@Overridepublic Connection getConnection() throwsSQLException {

Connection conn= null;//remove(Object o)//从列表中删除指定元素的第一个出现(如果存在)。

conn = pool.remove(0);

System.out.println("已从池中取走一个conn对象,还剩"+pool.size()+"个conn对象");returnconn;

}//提供returnConnection方法,用来把用了的数据库连接对象放回池中。

public void returnConnection(Connection conn) throwsSQLException{if(conn!=null && !conn.isClosed()){

pool.add(conn);

System.out.println("已成功还回对象");

}else{

System.out.println("这是一个空对象!");

}

}

@Overridepublic PrintWriter getLogWriter() throwsSQLException {//TODO Auto-generated method stub

return null;

}

@Overridepublic void setLogWriter(PrintWriter out) throwsSQLException {//TODO Auto-generated method stub

}

@Overridepublic void setLoginTimeout(int seconds) throwsSQLException {//TODO Auto-generated method stub

}

@Overridepublic int getLoginTimeout() throwsSQLException {//TODO Auto-generated method stub

return 0;

}

@Overridepublic Logger getParentLogger() throwsSQLFeatureNotSupportedException {//TODO Auto-generated method stub

return null;

}

@Overridepublic T unwrap(Class iface) throwsSQLException {//TODO Auto-generated method stub

return null;

}

@Overridepublic boolean isWrapperFor(Class> iface) throwsSQLException {//TODO Auto-generated method stub

return false;

}

@Overridepublic Connection getConnection(String username, String password) throwsSQLException {//TODO Auto-generated method stub

return null;

}

}

测试一下:

importjava.sql.Connection;importjava.sql.PreparedStatement;importjava.sql.ResultSet;importjava.sql.SQLException;

​importorg.junit.Test;

​/*** 这个类用来测试自定义的连接池

*@authorwjx

**/

public classtest {

@Testpublic voidtest_pool(){//声明数据库连接对象

Connection conn = null;//声明传输器对象

PreparedStatement pst = null;//声明结果集对象

ResultSet rs = null;//创建连接池对象

Pool pl = newPool();try{//获取连接器

conn =pl.getConnection();//创建传输器

String sql = "select * from user";

pst=conn.prepareStatement(sql);//获取结果集

rs =pst.executeQuery();//遍历结果集

while(rs.next()){

System.out.println("id="+rs.getInt(1)+" userName="+rs.getString(2)+" password=d"+rs.getString(3));

}

}catch(SQLException e) {//TODO Auto-generated catch block

e.printStackTrace();

}finally{//释放资源

try{

rs.close();

pst.close();

pl.returnConnection(conn);

}catch(SQLException e) {//TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

结果为:

已从池中取走一个conn对象,还剩4个conn对象

id=1 userName=u1 password=dp1

id=2 userName=u2 password=dp2

id=3 userName=u3 password=dp3

已成功还回对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值