Jdbc的普通封装

来源:互联网 发布:app软件培训多少钱 编辑:程序博客网 时间:2024/06/11 13:21

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

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

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

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

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

下面是xml的内容:

url=jdbc:mysql://localhost:3306/username=itaempassword=imitaemdbName=gdou_gymdriver=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; //数据库连接的urlprivate 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);}elsereturn -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 methodMethod[] 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 {// Fieldsprivate int fieldId;    //IDprivate int fieldTypeId;   //对应的场地类型IDprivate 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 accessorspublic 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;}@Overridepublic String toString() {return "Field [fieldId=" + fieldId + ", fieldTypeId=" + fieldTypeId+ ", fieldNumber=" + fieldNumber + ", fieldStatus="+ fieldStatus + ", fieldPic=" + fieldPic + ", fieldRemark="+ fieldRemark + ", fieldParttimes=" + fieldParttimes + "]";}}




0 0
原创粉丝点击