6.释放资源
说明:一般情况会将1,2,和6,三步封装进JDBCUtils类中,并使用配置文件来存储driverClass、jdbcUrl、user、password等信息
必须用到的三个对象:Connection连接,Statement/PreparedStatement传输器,ResultSet结果集
下面是简单的代码实现
配置文件:
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql://localhost:3306/jt_db
user=root
password=123456
JDBCUtils类
package JDBCUtils;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* 用于封装注册驱动,创建链接
*
*/
public class JDBCUtils {
private JDBCUtils(){
//为了不让别人创建实例,私有化,这样可以在别的类中不用new而直接调用这个类中的static方法
}
//将读取配置文件的操作放在静态块中,程序运行只调用一次
private static Properties p;
static{
//new配置文件对象
p = new Properties();
//加载配置文件地址
try {
p.load(new FileInputStream(
"src/main/resources/conf.properties"));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//祖册驱动,获取连接
public static Connection getConnection(){
try {
//1,注册驱动
Class.forName(p.getProperty("driverClass"));
//2,建立连接
Connection conn=null;
conn=DriverManager.getConnection(
p.getProperty("jdbcUrl"),
p.getProperty("user"),
p.getProperty("password"));
return conn;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 用于关闭连接
* @param conn 关闭连接对象,如果关闭不了,就把它的引用置为空,让GC去回收对象
* @param stat 关闭传输器对象,如果关闭不了,就把它的引用置为空,让GC去回收对象
* @param rs 关闭结果集对象,如果关闭不了,就把它的引用置为空,让GC去回收对象,preparedStatement对象是rs的子类,可直接传过来关闭
*/
public static void Close(Connection conn,Statement stat,ResultSet rs){
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}finally{
conn=null;
}
}
if(stat!=null){
try {
stat.close();
} catch (SQLException e) {
e.printStackTrace();
}finally{
stat=null;
}
}
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}finally{
rs=null;
}
}
}
}
测试类-- JDBC_CRUD (CRUD创建,查询,更新,删除)
package com.tedu.jdbc;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import JDBCUtils.JDBCUtils;
/**
* 单纯的使用Statement对象和PreparedStatement对象访问数据库进行查询,
* 未使用批处理和数据库连接池c3p0/dbcp
*/
public class JDBC_CRUD {
public static void main(String[] args) {
sel1();
}
//一,使用statement对象进行数据库访问
public static void sel(){
Connection conn=null;
Statement stat = null;
ResultSet rs=null;
//1,2,通过JDBCUtils注册驱动,获取链接
conn=JDBCUtils.getConnection();
try {
//3,获取传输器对象
stat=conn.createStatement();
//4,创建sql语句,并执行
String sql = "select * from t1";
rs = stat.executeQuery(sql);
while(rs.next()){
int id = rs.getInt(1);
String name=rs.getString(2);
System.out.println(id+":"+name);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//未使用连接池,所以此处为直接关闭连接
JDBCUtils.Close(conn, stat, rs);
}
}
//二,使用preparedStatement对象进行数据库访问
public static void sel1(){
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs = null;
//1,2
conn=JDBCUtils.getConnection();
//3,创建sql骨架,
String sql = "select * from t1 where id";
try {
//3.1将骨架传给prepareStateStatement对象
ps=conn.prepareStatement(sql);
//3.2设置骨架上的参数
ps.setInt(1, 500);
//3.3执行sql语句
rs=ps.executeQuery();
while(rs.next()){
int id = rs.getInt(1);
String name=rs.getString(2);
System.out.println(id+":"+name);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//没有使用连接池,所以这里的close是关闭连接
//因为preparedStatement是Statement的子类,所以,没有stat可以直接把子类传过去
JDBCUtils.Close(conn, ps, rs);
}
}
}
JDBC_CRUD_Batch 类,简单实现批处理
package com.tedu.jdbc;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import JDBCUtils.JDBCUtils;
/**
* 使用批处理插入记录
*注意:使用批处理一定要注意事务的自动提交要关闭掉,最后执行完SQL要使用手动提交事务
*/
public class JDBC_CRUD_Batch {
public static void main(String[] args) {
inst_ps();
}
//一,使用Statement对象进行批处理
public static void inst(){
Connection conn=null;
Statement stat=null;
ResultSet rs=null;
//1,2,注册驱动,获取链接
conn = JDBCUtils.getConnection();
try {
//关闭事务自动提交,改用手动提交
conn.setAutoCommit(false);
//3,获取Statement传输器对象
stat=conn.createStatement();
String sql="insert into t1 values(null,'dct')";
String sql1="insert into t1 values(null,'bfm')";
String sql2="insert into t1 values(null,'hcz')";
String sql3="insert into t1 values(null,'pgd')";
String sql4="insert into t1 values(null,'nzt')";
//添加到批处理中
stat.addBatch(sql);
stat.addBatch(sql1);
stat.addBatch(sql2);
stat.addBatch(sql3);
stat.addBatch(sql4);
//将批处理执行
stat.executeBatch();
//事务手动提交
conn.commit();
System.out.println("执行完毕!");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
JDBCUtils.Close(conn, stat, rs);
}
}
//二、使用PreparedStatement对象进行批处理
//注意:使用PreparedStatement对象要使用SQL骨架,一个骨架只能做CRUD其中一个功能,不够灵活,
//如果用到的批处理中CRUD都 有,那么就使用Statement对象做批处理
public static void inst_ps(){
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
//1,2,注册驱动,获取链接
conn=JDBCUtils.getConnection();
//3,创建PreparedStatement对象
//3.1生成sql骨架
String sql = "update t1 set name='NZT' where name=?";
String sql1="insert into t1 values(null,?)";
try {
//关闭事务的自动提交
conn.setAutoCommit(false);
//将骨架传入preparedStatement对象中
ps=conn.prepareStatement(sql1);
for(int i=0;i<10;i++){
//将骨架内容补全后,一个一个的添加到批处理中
ps.setString(1, "NZT"+i);
ps.addBatch();
}
//执行批处理
ps.executeBatch();
//手动提交事务
conn.commit();
System.out.println("执行完毕!");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
JDBCUtils.Close(conn, ps, rs);
}
}
}
自己写的数据库连接池--未优化
package com.tedu.poll;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Logger;
import javax.sql.DataSource;
import JDBCUtils.JDBCUtils;
/**
* 1,写一个类,实现 DataSource 接口
*/
public class MyPool implements DataSource {
/**
* 2,创建一个容器,当做连接池使用,这里用LinkedList
*/
private static List list=
new LinkedList();
/**
* 3,提供一个静态块,在程序启动时,初始化一批连接放在连接池中共享
*/
private static Connection conn;
static{
for (int i = 0; i < 5; i++) {
conn=JDBCUtils.getConnection();
list.add(conn);
}
}
/**
* 4,实现getConnection方法,用来获取连接池中的链接
*/
public Connection getConnection() throws SQLException {
//如果连接池里面的连接拿完了,那就再次加入5个连接
if(list.size()==0){
for(int i=0;i<5;i++){
conn=JDBCUtils.getConnection();
list.add(conn);
}
}
conn = list.remove(0);//get()方法是获得,使用后集合里面还有,remove()方法是移除,拿完就没了
System.out.println("取连接,数量"+list.size());
return conn;
}
/**
*,5,还连接
*/
public void returnConn(Connection conn){
try {
//如果连接不是空的,并且连接没有被关闭,就将连接添加到连接池中
if(conn!=null && !conn.isClosed()){
list.add(conn);
System.out.println("还连接,连接数"+list.size());
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
测试自定义连接池
package com.tedu.poll;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* 测试自定义连接池
*
*/
public class TestMyTool {
public static void main(String[] args) {
//查询t1表中的ID为3的记录
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
MyPool p = new MyPool();
try {
conn=p.getConnection();
//3,创建PreparedStatement对象
String sql="select * from t1 where id=?";
ps=conn.prepareStatement(sql);
ps.setInt(1, 3);
rs=ps.executeQuery();
while(rs.next()){
int id=rs.getInt(1);
String name=rs.getString(2);
System.out.println(id+":"+name);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//这里归还连接,而不是关闭连接
p.returnConn(conn);
}
}
}
使用c3p0数据库连接池,需要重新配置JDBCUtils类(在文尾)
package test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.mchange.v2.c3p0.ComboPooledDataSource;
/**
* 使用c3p0连接池
*/
public class C3p0 {
public static void main(String[] args) {
Connection conn=null;
PreparedStatement ps=null;
ResultSet rs=null;
//0,导入c3p0的jar包
//1,写c3p0的XML配置文件,放在源文件夹中,c3p0会自动扫描配置文件并应用,省去了1,注册驱动环节,不用管它
//但是文件名字必须为c3p0-config.xml,使用c3p0就不用再配置JDBCUtils中的getConnection方法了
//2,从c3p0连接池获取链接-->new一个连接池对象
ComboPooledDataSource pool = new ComboPooledDataSource();
try {
//3,获取一个连接给conn
conn=pool.getConnection();
//4,创建SQL骨架,创建传输器对象
String t1="t1";
String sql="select * from "+t1;
//4.1将骨架传过去
ps=conn.prepareStatement(sql);
//4.2设置骨架参数,不可以直接传表名,但是可以在上面的SQL语句中进行字符串拼接
// ps.setString(1, t1);
//5,执行SQL语句
rs=ps.executeQuery();
//6,获取结果
while(rs.next()){
int id=rs.getInt(1);
String name=rs.getString(2);
System.out.println(id+":"+name);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//7,还连接,因为这里使用的是c3p0连接池,c3p0连接池对close方法进行了改造,
//close方法自动变成了还连接,不再是关闭资源!!!这点要注意
JDBCUtils.JDBCUtils.Close(conn, ps, rs);
}
}
}
1、导入开发包
2、创建数据库连接池
ComboPooledDataSource cpds = new ComboPooledDataSource();
3、设置数据库连接的基本信息
配置c3p0-config.xml配置文件(1)方式一:
cpds.setDriverClass("com.mysql.jdbc.Driver");
cpds.setJdbcUrl("jdbc:mysql:///mydb1");
cpds.setUser("root");
cpds.setPassword("root");
(2)方式二:推荐!!
在类目录下(开发时可以放在src或者类似的源码目录(源码目录指的是fileànewàSource folder出来的文件夹,源码目录下可以新建包,普通文件夹下不可以)下), 添加一个c3p0-config.xml文件(文件名必须这样写), 配置内容如下:
(3)方式三:
在类目录下(开发时可以放在src或者类似的源码目录下), 添加一个c3p0.properties文件, 配置内容如下:
4,通过连接池实例调用getConnection方法获取连接!
5,最后调用连接对象上的close方法,用来将连接还回连接池中
***********************************************************************************************************************
重新配置JDBCUtils类,使用c3p0数据库连接池之后,各个类更为简单了
package com.tedu.utils;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* 使用c3p0数据库连接池后,这个类就只剩下关闭资源的功能
* 其他功能已经在测试类中铺设好,使用c3p0更为简单一些
*/
public class JDBCUtils2 {
private JDBCUtils2(){//为了不让别人创建实例,私有化
}
/**
* 将制定的资源关闭(释放)
* @param conn 链接对象
* @param stat 传输器对象
* @param rs 结果集对象
*/
public static void close(Connection conn,Statement stat,ResultSet rs){
if(rs !=null){
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
rs=null;
}
}
if(stat != null){
try {
stat.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
stat=null;
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
conn=null;
}
}
}
}