Jdbc的普通封装

嗯,大家肯定是经常使用jdbc完成一些基本的数据库操作,但是每次有没有发现都是差不多同样子的操作呢?为了解决这个问题,下面给出一个基本的jdbc封装。在这个列子中,

采用了单例设计模式,并且很好的控制了线程并发问题。因为数据的操作,每个Connection, Statement, PreparedStatement,ResultSet对象,都可能造成线程并发问题,所以在这个

类里面,全部的对象都是在方法里面定义,这样子,每个方法都拥有自己的运行堆栈,从而在使用单列模式的情况下,也不会有线程并发问题。有时候,在我们刚开始使用jdbc的

时候,会直接把Connetion, Statement, PreparedStatement, ResultSet的对象定义为一个类的属性...那样子很容易造成并发问题。

这个类同样把数据库的配置,放在一个xml文件中,这样子更具有灵活性。在修改xml的情况下,既可以完成数据库的更换。

下面是xml的内容:

url=jdbc:mysql://localhost:3306/
username=itaem
password=imitaem
dbName=gdou_gym
driver=org.gjt.mm.mysql.Driver


下面是封装的JdbcTool工具类:
package net.itaem.tool;


import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import net.itaem.po.Field;


/**
 * 操作数据库的工具类,这个类负责建立于数据库的连接,负责执行update, insert, delete等基本的数据库操作
 * 这个类大家可以直接使用,不需要考虑过多的线程问题
 * 这个类写了通用的update, insert, delete等数据库访问方法,具体到特殊的查询,以及含有事务的sql组合
 * 大家可以直接写在自己的dao中
 * 注意点:调用了getConnection()之后,记得在宿主程序中关闭你所获得的Connection变量
 * @author luohong
 * @date 2014-03-09
 * */
public class JdbcTool {


private static JdbcTool instance = new JdbcTool();


//这些属性不可以修改,只允许直接从 jdbc.cfg.properties读取
private static String dbName; //数据库名字
private static String url; //数据库连接的url
private static String username;  //数据库用户名
private static String password;  //密码


/**
 * 解析数据库的配置文件
 * 从配置文件中读取数据库连接的 url, username, password, driver, database name等各种信息
 * 以后要修改数据库的链接地址,直接修改配置文件,不要修改该类
 * */
static{
try {


Properties properties = new Properties();
InputStream inputStream = JdbcTool.class.getClassLoader().getResourceAsStream("jdbc.cfg.properties");


properties.load(inputStream);
//加载数据库驱动
Class.forName((String)properties.get("driver"));


dbName = (String)properties.getProperty("dbName");
url = (String)properties.getProperty("url");
password = (String)properties.getProperty("password");
username =  (String)properties.getProperty("username");
} catch (Exception e) {
throw new RuntimeException("加载mysql驱动失败");
}
}


/**
 * 这个类的访问接口,返回这个类的实例,每次访问,返回的都是同一个实例
 * */
public static JdbcTool getJdbcToolInstance(){
return instance;
}


/**
 * 采用单列设计模式
 * */
private JdbcTool(){


}


/**
 * 获取数据库连接
 * 返回的每个Connection都是 new 出来的唯一Connection
 * @return Connection 返回数据库的链接
 * @exception RuntimeException 如果获取数据库连接失败,直接抛出运行时异常,调用者不需要捕获该异常
 * */
public Connection getConnection(){
try {
Connection conn = DriverManager.getConnection(url + dbName, username, password);
return conn;
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("获取数据库连接失败" + ",url:" + url + dbName + ",username:" + username + ", password:" + password);
}
}


/**
 * 执行insert, update, delete的sql语句,如果操作影响结果
 * @param sql 要执行的sql语句,形式:insert into student(name, number) values (?,?)
 * @param args 要执行数据库的sql参数,如果为null,直接执行sql语句
 * @return 返回记录修改的数目,如果出现异常,返回 -1
 * */
public int executeUpdate(String sql, Object[] args){
Connection conn = getConnection();


PreparedStatement ps = null;
try {
ps = conn.prepareStatement(sql);


if(args != null && args.length > 0)
//注入sql ? 的实际内容
for(int i=0; i<args.length; i++)
ps.setObject(i + 1, args[i]);


//如果没有参数,直接执行
return ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
return -1;
}finally{
//关闭数据库连接
try {
ps.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}


}


}

/**
 * 批量执行sql语句,调用该方法之间,必须组装好sql语句
 * sql语句只能是增加,删除,修改三种类型的语句
 * @param sqlArray 要批量执行的sql语句
 * @return 返回批量执行后的int数组
 * @exception SQLException
 * */
public int[] executeUpdateBatch(String[] sqlArray){
Connection conn = getConnection();


Statement statement = null;
try {
statement = conn.createStatement();
for(String sql : sqlArray)
statement.addBatch(sql);
return statement.executeBatch();
} catch (SQLException e) {
e.printStackTrace();
}finally{
//关闭数据库连接
try {
statement.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return null;
}

/**专门用于插入主键自动增长的数据库表的操作,返回值为自动增长的主键值
 * @author 少钦
 * @param sql
 * @param objs
 * @return 插入成功的自动增长的主键,如果没有成功则返回-1
 */
public int add(String sql,Object[] objs){
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
JdbcTool tool=JdbcTool.getJdbcToolInstance();
conn = tool.getConnection();
st = conn.prepareStatement(sql,PreparedStatement.RETURN_GENERATED_KEYS);
for (int i = 0; objs != null && i < objs.length; i++) {
st.setObject(i + 1, objs[i]);
}
st.executeUpdate();
rs = st.getGeneratedKeys();
if (rs.next()) {
return rs.getInt(1);
}else
return -1;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("获取数据过程中出现异常" + e);
} finally {
JdbcTool.release(conn,st,rs);
}
}

/**专门用来关闭数据库连接的方法,st可以PreparedStatement(Statement是pt的父类)
 * @author 少钦
 * @param conn
 * @param st PreparedStatement或者Statement
 * @param rs
 */
public static void release(Connection conn,Statement st,ResultSet rs){
try{
if(rs!=null){
try{
rs.close();
}catch(SQLException e){
throw e;
}
}
if(st!=null){
try{
st.close();
}catch(SQLException e){
throw e;
}
}
if(conn!=null){
try{
conn.close();
}catch(SQLException e){
throw e;
}
}
}catch (SQLException e) {
throw new RuntimeException("关闭数据库连接时发生异常!异常信息:"+e);
}
}




public static void main(String[] args) throws Exception{
System.out.println(getTableList("select * from field where field_id>?", new Object[]{10}, new Field()));
}




/**
 * 根据sql,返回对象的集合
 * 这个方法的使用要求:传入的sql属于预处理的sql
 * args可以为null,或者是一个没有内容的Object[]数组
 * object是要封装的数据类型,在每次方法返回的时候,必须要转换为你所需要的数据类型,当然,读者可以自己修改为泛型方法,那样子封装更加完美
 * 
 * bug:因为封装过程中,每次只是修改Object的内容,然后添加到集合中,所以这个集合中的所有对象都是同一个对象...不可以使用Set进行转换
 * 
 * @param args sql的参数
 * @param object 要封装的类型
 * 
 * @throws SQLException 
 * @throws InvocationTargetException 
 * @throws IllegalAccessException 
 * @throws IllegalArgumentException 
 * */
public static List<Object> getTableList(String sql, Object[] args, Object object) throws SQLException, 
    IllegalArgumentException, IllegalAccessException, InvocationTargetException{

Connection conn = getJdbcToolInstance().getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = null;

if(args == null || args.length ==0){   //没有参数
rs = ps.executeQuery();   //查询
}else{   //有参数
for(Object obj: args){
ps.setObject(1, obj);
} 
rs = ps.executeQuery();
}


ResultSetMetaData rsmd = rs.getMetaData();

int columnCount = rsmd.getColumnCount();  //the column of the table

@SuppressWarnings("rawtypes")
Class clazz = object.getClass();
//获得所有的属性
java.lang.reflect.Field[] fields = clazz.getDeclaredFields();


String[] methodNames = new String[fields.length];
//get all object method
Method[] methods = object.getClass().getDeclaredMethods();  


//获得所有的方法名
for(int i=0; i<fields.length; i++){
methodNames[i] = "set" + fields[i].getName().substring(0, 1).toUpperCase() + fields[i].getName().substring(1);
}

//封装存在的问题:因为这里每次都把参数object加入到集合中,所以这里所有的集合对象都是同一个对象
        List<Object> objList = new ArrayList<Object>();
        
        Set<Object> objSet = new HashSet<Object>();
        
        while(rs.next()){
for(int i=0; i<columnCount; i++){
String methodName = methodNames[i];
for(Method method: methods){
if(method.getName().equalsIgnoreCase(methodName)){
//设置对象的属性
method.invoke(object, rs.getObject(rsmd.getColumnName(i+1)));
}
}
objList.add(object);
}
}
        
        //objSet.addAll(objList);
        //System.out.println("the set size is " + objSet.size());    //打印的结果为1!!!!
return objList;
}
}


//使用到的Field类对象
package net.itaem.po;


import java.util.HashSet;
import java.util.Set;


/**
 * 
 * @Description:场地po类 
 * @operate:
 * @author sen
 * @date 2014-3-11
 */
public class Field implements java.io.Serializable {


// Fields


private int fieldId;    //ID
private int fieldTypeId;   //对应的场地类型ID
private String fieldNumber;   //场地序号 /场地名称
private boolean fieldStatus;  //场地的状态 fieldStatus=true为开启状态  fieldStatus=false为关闭状态
private String fieldPic;    //场地存放图片路径
private String fieldRemark;   //场地备注
private Set fieldParttimes = new HashSet(0);  //场地对应的场地时间段


// Constructors


/** default constructor */
public Field() {
}


/** minimal constructor */
public Field(int fieldId) {
this.fieldId = fieldId;
}


/** full constructor */
public Field(int fieldId, int fieldTypeId, String fieldNumber,
boolean fieldStatus, String fieldPic, String fieldRemark,
Set fieldParttimes) {
this.fieldId = fieldId;
this.fieldTypeId = fieldTypeId;
this.fieldNumber = fieldNumber;
this.fieldStatus = fieldStatus;
this.fieldPic = fieldPic;
this.fieldRemark = fieldRemark;
this.fieldParttimes = fieldParttimes;
}


public Field(int fieldId, int fieldTypeId, String fieldNumber,
String fieldPic, String fieldRemark) {
this.fieldId = fieldId;
this.fieldTypeId = fieldTypeId;
this.fieldNumber = fieldNumber;

this.fieldPic = fieldPic;
this.fieldRemark = fieldRemark;
}
public Field(int fieldTypeId, String fieldNumber,
String fieldPic, String fieldRemark) {
this.fieldTypeId = fieldTypeId;
this.fieldNumber = fieldNumber;
this.fieldPic = fieldPic;
this.fieldRemark = fieldRemark;
}
// Property accessors


public int getFieldId() {
return this.fieldId;
}


public void setFieldId(int fieldId) {
this.fieldId = fieldId;
}



public int getFieldTypeId() {
return fieldTypeId;
}


public void setFieldTypeId(int fieldTypeId) {
this.fieldTypeId = fieldTypeId;
}


public String getFieldNumber() {
return this.fieldNumber;
}


public void setFieldNumber(String fieldNumber) {
this.fieldNumber = fieldNumber;
}


public boolean getFieldStatus() {
return this.fieldStatus;
}


public void setFieldStatus(boolean fieldStatus) {
this.fieldStatus = fieldStatus;
}


public String getFieldPic() {
return this.fieldPic;
}


public void setFieldPic(String fieldPic) {
this.fieldPic = fieldPic;
}


public String getFieldRemark() {
return this.fieldRemark;
}


public void setFieldRemark(String fieldRemark) {
this.fieldRemark = fieldRemark;
}


public Set getFieldParttimes() {
return this.fieldParttimes;
}


public void setFieldParttimes(Set fieldParttimes) {
this.fieldParttimes = fieldParttimes;
}


@Override
public String toString() {
return "Field [fieldId=" + fieldId + ", fieldTypeId=" + fieldTypeId
+ ", fieldNumber=" + fieldNumber + ", fieldStatus="
+ fieldStatus + ", fieldPic=" + fieldPic + ", fieldRemark="
+ fieldRemark + ", fieldParttimes=" + fieldParttimes + "]";
}


}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值