JavaWeb开发与代码的编写(十六)
JDBC进行批处理
在实际的项目开发中,有时候需要向数据库发送一批SQL语句执行,这时应避免向数据库一条条的发送执行,而应采用JDBC的批处理机制,以提升执行效率。 JDBC实现批处理有两种方式:statement和preparedstatement
使用Statement完成批处理
1、使用Statement对象添加要批量执行SQL语句,如下:
Statement.addBatch(sql1);
Statement.addBatch(sql2);
Statement.addBatch(sql3);
2、执行批处理SQL语句:Statement.executeBatch(); 3、清除批处理命令:Statement.clearBatch();
使用Statement完成批处理范例
1、编写测试的SQL脚本创建表
create table testbatch
(
id int primary key,
name varchar(20)
);
2、编写测试代码,如下所示:
package me.gacl.demo;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import me.gacl.utils.JdbcUtils;
import org.junit.Test;
/**
* @ClassName: JdbcBatchHandleByStatement
* @Description: 使用Statement实现JDBC批处理操作
*
*/
public class JdbcBatchHandleByStatement {
@Test
public void testJdbcBatchHandleByStatement(){
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
String sql1 = "insert into testbatch(id,name) values(1,'aaa')";
String sql2 = "insert into testbatch(id,name) values(2,'bbb')";
String sql3 = "insert into testbatch(id,name) values(3,'CCC')";
String sql4 = "insert into testbatch(id,name) values(4,'DDD')";
String sql5 = "update testbatch set name='gacl' where id=1";
String sql6 = "insert into testbatch(id,name) values(5,'FFF')";
String sql7 = "delete from testbatch where id=2";
st = conn.createStatement();
//添加要批量执行的SQL
st.addBatch(sql1);
st.addBatch(sql2);
st.addBatch(sql3);
st.addBatch(sql4);
st.addBatch(sql5);
st.addBatch(sql6);
st.addBatch(sql7);
//执行批处理SQL语句
st.executeBatch();
//清除批处理命令
st.clearBatch();
}catch (Exception e) {
e.printStackTrace();
}finally{
JdbcUtils.release(conn, st, rs);
}
}
}
采用Statement.addBatch(sql)方式实现批处理的优缺点
采用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');
使用PreparedStatement完成批处理
使用PreparedStatement完成批处理范例
测试代码如下:
package me.gacl.demo;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import me.gacl.utils.JdbcUtils;
import org.junit.Test;
/**
* @ClassName: JdbcBatchHandleByStatement
* @Description: 使用prepareStatement实现JDBC批处理操作
*
*/
public class JdbcBatchHandleByPrepareStatement {
@Test
public void testJdbcBatchHandleByPrepareStatement(){
long starttime = System.currentTimeMillis();
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
String sql = "insert into testbatch(id,name) values(?,?)";
st = conn.prepareStatement(sql);
for(int i=1;i
com.mysql.jdbc.Driver
jdbc:mysql://localhost:3306/jdbcstudy
root
XDP
5
10
5
20
com.mysql.jdbc.Driver
jdbc:mysql://localhost:3306/jdbcstudy
root
XDP
5
10
5
20
如下图所示:
3、在获取数据库连接的工具类(如jdbcUtils)的静态代码块中创建池
1 package me.gacl.util;
2
3 import java.sql.Connection;
4 import java.sql.ResultSet;
5 import java.sql.SQLException;
6 import java.sql.Statement;
7 import com.mchange.v2.c3p0.ComboPooledDataSource;
8
9 /**
10 * @ClassName: JdbcUtils_C3P0
11 * @Description: 数据库连接工具类
15 */
16 public class JdbcUtils_C3P0 {
17
18 private static ComboPooledDataSource ds = null;
19 //在静态代码块中创建数据库连接池
20 static{
21 try{
22 //通过代码创建C3P0数据库连接池
23 /*ds = new ComboPooledDataSource();
24 ds.setDriverClass("com.mysql.jdbc.Driver");
25 ds.setJdbcUrl("jdbc:mysql://localhost:3306/jdbcstudy");
26 ds.setUser("root");
27 ds.setPassword("XDP");
28 ds.setInitialPoolSize(10);
29 ds.setMinPoolSize(5);
30 ds.setMaxPoolSize(20);*/
31
32 //通过读取C3P0的xml配置文件创建数据源,C3P0的xml配置文件c3p0-config.xml必须放在src目录下
33 //ds = new ComboPooledDataSource();//使用C3P0的默认配置来创建数据源
34 ds = new ComboPooledDataSource("MySQL");//使用C3P0的命名配置来创建数据源
35
36 }catch (Exception e) {
37 throw new ExceptionInInitializerError(e);
38 }
39 }
40
41 /**
42 * @Method: getConnection
43 * @Description: 从数据源中获取数据库连接
45 * @return Connection
46 * @throws SQLException
47 */
48 public static Connection getConnection() throws SQLException{
49 //从数据源中获取数据库连接
50 return ds.getConnection();
51 }
52
53 /**
54 * @Method: release
55 * @Description: 释放资源,
56 * 释放的资源包括Connection数据库连接对象,负责执行SQL命令的Statement对象,存储查询结果的ResultSet对象
58 *
59 * @param conn
60 * @param st
61 * @param rs
62 */
63 public static void release(Connection conn,Statement st,ResultSet rs){
64 if(rs!=null){
65 try{
66 //关闭存储查询结果的ResultSet对象
67 rs.close();
68 }catch (Exception e) {
69 e.printStackTrace();
70 }
71 rs = null;
72 }
73 if(st!=null){
74 try{
75 //关闭负责执行SQL命令的Statement对象
76 st.close();
77 }catch (Exception e) {
78 e.printStackTrace();
79 }
80 }
81
82 if(conn!=null){
83 try{
84 //将Connection连接对象还给数据库连接池
85 conn.close();
86 }catch (Exception e) {
87 e.printStackTrace();
88 }
89 }
90 }
91 }
测试C3P0数据源
package me.gacl.test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import org.junit.Test;
import me.gacl.util.JdbcUtils_C3P0;
import me.gacl.util.JdbcUtils_DBCP;
public class DataSourceTest {
@Test
public void c3p0DataSourceTest() {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try{
//获取数据库连接
conn = JdbcUtils_C3P0.getConnection();
String sql = "insert into test1(name) values(?)";
st = conn.prepareStatement(sql);
st.setString(1, "gacl"); st.executeUpdate();
//获取数据库自动生成的主键
rs = st.getGeneratedKeys();
if(rs.next()){
System.out.println(rs.getInt(1));
}
}catch (Exception e) {
e.printStackTrace();
}finally{
//释放资源
JdbcUtils_C3P0.release(conn, st, rs);
}
}
}
配置Tomcat数据源
在实际开发中,我们有时候还会使用服务器提供给我们的数据库连接池,比如我们希望Tomcat服务器在启动的时候可以帮我们创建一个数据库连接池,那么我们在应用程序中就不需要手动去创建数据库连接池,直接使用Tomcat服务器创建好的数据库连接池即可。要想让Tomcat服务器在启动的时候帮我们创建一个数据库连接池,那么需要简单配置一下Tomcat服务器。
JNDI技术简介
JNDI(Java Naming and Directory Interface),Java命名和目录接口,它对应于J2SE中的javax.naming包, 这 套API的主要作用在于:它可以把Java对象放在一个容器中(JNDI容器),并为容器中的java对象取一个名称,以后程序想获得Java对象,只需 通过名称检索即可。其核心API为Context,它代表JNDI容器,其lookup方法为检索容器中对应名称的对象。
Tomcat服务器创建的数据源是以JNDI资源的形式发布的,所以说在Tomat服务器中配置一个数据源实际上就是在配置一个JNDI资源,通过查看Tomcat文档,我们知道使用如下的方式配置tomcat服务器的数据源:
服务器创建好数据源之后,我们的应用程序又该怎么样得到这个数据源呢,Tomcat服务器创建好数据源之后是以JNDI的形式绑定到一个JNDI容器中的,我们可以把JNDI想象成一个大大的容器,我们可以往这个容器中存放一些对象,一些资源,JNDI容器中存放的对象和资源都会有一个独一无二的名称,应用程序想从JNDI容器中获取资源时,只需要告诉JNDI容器要获取的资源的名称,JNDI根据名称去找到对应的资源后返回给应用程序。我们平时做javaEE开发时,服务器会为我们的应用程序创建很多资源,比如request对象,response对象,服务器创建的这些资源有两种方式提供给我们的应用程序使用:第一种是通过方法参数的形式传递进来,比如我们在Servlet中写的doPost和doGet方法中使用到的request对象和response对象就是服务器以参数的形式传递给我们的。第二种就是JNDI的方式,服务器把创建好的资源绑定到JNDI容器中去,应用程序想要使用资源时,就直接从JNDI容器中获取相应的资源即可。
对于上面的name="jdbc/datasource"数据源资源,在应用程序中可以用如下的代码去获取
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
dataSource = (DataSource)envCtx.lookup("jdbc/datasource");
此种配置下,数据库的驱动jar文件需放置在tomcat的lib下
配置Tomcat数据源
1、在Web项目的WebRoot目录下的META-INF目录创建一个context.xml文件
如下图所示:
2、在context.xml文件配置tomcat服务器的数据源
3、将数据库的驱动jar文件需放置在tomcat的lib下
4、在获取数据库连接的工具类(如jdbcUtils)的静态代码块中获取JNDI容器中的数据源
1 package me.gacl.util;
2
3 import java.sql.Connection;
4 import java.sql.ResultSet;
5 import java.sql.SQLException;
6 import java.sql.Statement;
7 import javax.naming.Context;
8 import javax.naming.InitialContext;
9 import javax.sql.DataSource;
10
11 /**
12 * @ClassName: JdbcUtils_DBCP
13 * @Description: 数据库连接工具类
16 *
17 */
18 public class JdbcUtils_JNDI {
19
20 private static DataSource ds = null;
21 //在静态代码块中创建数据库连接池
22 static{
23 try{
24 //初始化JNDI
25 Context initCtx = new InitialContext();
26 //得到JNDI容器
27 Context envCtx = (Context) initCtx.lookup("java:comp/env");
28 //从JNDI容器中检索name为jdbc/datasource的数据源
29 ds = (DataSource)envCtx.lookup("jdbc/datasource");
30 }catch (Exception e) {
31 throw new ExceptionInInitializerError(e);
32 }
33 }
34
35 /**
36 * @Method: getConnection
37 * @Description: 从数据源中获取数据库连接
39 * @return Connection
40 * @throws SQLException
41 */
42 public static Connection getConnection() throws SQLException{
43 //从数据源中获取数据库连接
44 return ds.getConnection();
45 }
46
47 /**
48 * @Method: release
49 * @Description: 释放资源,
50 * 释放的资源包括Connection数据库连接对象,负责执行SQL命令的Statement对象,存储查询结果的ResultSet对象
52 *
53 * @param conn
54 * @param st
55 * @param rs
56 */
57 public static void release(Connection conn,Statement st,ResultSet rs){
58 if(rs!=null){
59 try{
60 //关闭存储查询结果的ResultSet对象
61 rs.close();
62 }catch (Exception e) {
63 e.printStackTrace();
64 }
65 rs = null;
66 }
67 if(st!=null){
68 try{
69 //关闭负责执行SQL命令的Statement对象
70 st.close();
71 }catch (Exception e) {
72 e.printStackTrace();
73 }
74 }
75
76 if(conn!=null){
77 try{
78 //将Connection连接对象还给数据库连接池
79 conn.close();
80 }catch (Exception e) {
81 e.printStackTrace();
82 }
83 }
84 }
85 }
写一个Servlet测试JNDI数据源
package me.gacl.test;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import me.gacl.util.JdbcUtils_JNDI;
public class JNDITest extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Connection conn = null; PreparedStatement st = null;
ResultSet rs = null;
try{
//获取数据库连接
conn = JdbcUtils_JNDI.getConnection(); String sql = "insert into test1(name) values(?)";
st = conn.prepareStatement(sql);
st.setString(1, "gacl");
st.executeUpdate();
//获取数据库自动生成的主键
rs = st.getGeneratedKeys();
if(rs.next()){
System.out.println(rs.getInt(1));
}
}catch (Exception e) {
e.printStackTrace();
}finally{
//释放资源
JdbcUtils_JNDI.release(conn, st, rs);
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}