使用JDBC进行批处理

当需要向数据库发送一批SQL语句执行时,应避免向数据库一条条的发送执行,而应采用JDBC的批处理机制,以提升执行效率。

2、实现批处理有两种方式。

l 第一种方式:Statement.addBatch(sql)  Statement中有一个集合属性list存储所有的sql),执行批处理SQL语句
executeBatch()方法:执行批处理命令
clearBatch()方法:清除批处理命令

案例3,批处理。

准备:

l com.hbsi.utils包下的DBManager类负责获得连接以及资源的释放。

l 属性文件db.properties保存了建立连接时需要的参数。
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/demodb
username=root
password=root

l MySQL的驱动

l 创建表
create table testbatch
(
    id int primary key,
    name varchar(100)
) ;

代码编写:Demo3.java

public void test1() {

Connection conn = null;

Statement st = null;

ResultSet rs = null;

try{

conn = DBManager.getConnection();

String sql1 = "insert into testbatch(id,name) values(1,'aa')";

String sql2 = "insert into testbatch(id,name) values(2,'bb')";

String sql3 = "delete from testbatch where id=1";

st = conn.createStatement();

st.addBatch(sql1);//sql语句加入到批中

st.addBatch(sql2);

st.addBatch(sql3);

//该方法返回值为int[],返回的是每条sql语句执行后对表中记录的影响行数

st.executeBatch();

st.clearBatch();

}catch (Exception e) {

throw new RuntimeException(e);

}finally{

DBManager.release(conn, st, rs);

}

}

l 采用Statement.addBatch(sql)方式实现批处理的优点:可以向数据库发送多条不同的SQL语句。缺点一是SQL语句没有预编译,二是当向数据库发送多条语句相同,但仅参数不同的SQL语句时,需重复写上很多条SQL语句。例如:

Insert into user(name,password) values(aa,111);

Insert into user(name,password) values(bb,222);

Insert into user(name,password) values(cc,333);

Insert into user(name,password) values(dd,444);

l 实现批处理的第二种方式:PreparedStatement.addBatch()

案例4,向数据库的表中插入1亿条记录。

public void test2() {

long starttime = System.currentTimeMillis();

Connection conn = null;

PreparedStatement st = null; //list

ResultSet rs = null;

try{

conn = DBManager.getConnection();

String sql = "insert into testbatch(id,name) values(?,?)";

st = conn.prepareStatement(sql);

for(int i=0;i<10000004;i++){

st.setInt(1, i);

st.setString(2, "aa" + i);

st.addBatch();

if(i%1000==0){

st.executeBatch();

st.clearBatch();

}

}

st.executeBatch();//为了保证最后那4sql语句也会被提交

}catch (Exception e) {

throw new RuntimeException(e);

}finally{

DBManager.release(conn, st, rs);

}

long endtime = System.currentTimeMillis();

System.out.println("共花了: " + (endtime-starttime)/1000 + "");

}

代码段:conn = DBManager.getConnection();

String sql = "insert into testbatch(id,name) values(?,?)";

st = conn.prepareStatement(sql);//预编译一下sql语句

st.setInt(1, 1);

st.setString(2, "aa");

//写到这在st中就有一条完整的sql语句了,因此可以加入批中

st.addBatch();

我们可以将上面的三条语句加入循环中即可向st中添加多条sql语句,所以我们可以写一个循环,循环1亿次,添加1亿条记录。即:

for(int i=0;i<10000000;i++){

st.setInt(1, i);

st.setString(2, "aa" + i);

st.addBatch();

}

这样写完后执行,发现数据库的表中并没有我们想象的1亿条记录。为什么呢?

st语句对象中有一个list对象保存加入的sql语句,每条sql语句是要占一定内存的(8~9个字节),当你加1亿条sql语句时会占多少内存?内存一下就崩溃了。因此千万不要直接把这一亿条sql语句都加入到批中,使用如下的代码:

for(int i=0;i<10000000;i++){

st.setInt(1, i);

st.setString(2, "aa" + i);

st.addBatch();

if(i%1000==0){//1000条记录做成一批

st.executeBatch();//提交给mysql去执行

st.clearBatch();//提交后,要把批中的sql语句清掉

}

}

这样还有问题:如果是循环1千万零4次,那最后的4sql语句会提交给MySQL执行吗?不会!因此在该循环结束后还要有一条st.executeBatch()语句的执行。

这个程序写完后运行时花费的时间会很长,差不多3-4个小时。而在oracle下会很快,几分钟吧。

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

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

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

三、如何获取数据库自动生成的主键

这部分内容用在哪里呢?例如,老公表和老婆表

老公表

id

name

 4

张三

老婆表

id

name

h_id

1

aaa

4

老公表中id是自动增长的,向老公表中插入一条记录,姓名为“张三”,id自动增长为4。这时向老婆表中插入一条记录,姓名为“aaa”,她老公为“张三”,这时我们就需要获取老公表中自动增长的id值去更新老婆表中的记录。

案例:

create database jdbc character set utf8 collate utf8_general_ci;

use jdbc;

create table users(

id int primary key auto_increment,

name varchar(40),

password varchar(40),

email varchar(60),

birthday date

)

现在向该表中插入一行记录,然后得到自动增长的id

insert into users(name,password,email,birthday) values('zs','1234','[email protected]','1990-1-1');

insert into users(name,password,email,birthday) values('lisi','1234','[email protected]','1990-3-1');

编写Java代码:Demo4.java

Connection conn = JdbcUtil.getConnection();

String sql = "insert into user(name,password,email,birthday) 

values('abc','123','[email protected]','1978-08-08')";

PreparedStatement st = conn.

prepareStatement(sql,Statement.RETURN_GENERATED_KEYS );

//Statement.RETURN_GENERATED_KEYS参数可带可不带,不带该参数时也可得到自动增长的id,因为MySQL的驱动默认就是可以返回自动增长的id的。如果得不到自动增长的id,你就要小心了,就需要传递该参数。该参数的取值还可以是Statement.NO_GENERATED_KEY,意思相反。但是当我们真的设置为NO_GENERATED_KEY时,还是可以返回自动增长的id,这时因为JDBC只是一种规范,mysql有没有按照规范去实现?从这里可以看出mysql根本没有安装规范去实现。

st.executeUpdate();

//上面的语句执行完,就向数据库的表中添加了一条记录,我们想获得刚添加的记录自动增长的id,方法:

ResultSet rs = st.getGeneratedKeys();  //得到插入行的主键,结果集中只有一条记录

if(rs.next())

System.out.println(rs.getObject(1)); //rs.getInt(1)

你可能感兴趣的:(使用JDBC进行批处理)