jdbc篇第8課:進一步封裝jdbc
阿新 • • 發佈:2018-11-28
這節課我們來進一步封裝jdbc
首先來分析下,jdbc的使用:
jdbc使用:
1. 建立好表對應的類(我們稱為bean),要求每一列對應一個屬性,且資料型別對應上
2. 建立連線,獲取Connection物件
3. 使用Connection物件獲取Statement或PreparedStatement物件
4. 寫好sql
5. 使用Statement或PreparedStatement執行查詢語句,如果是select語句,獲取ResultSet物件,並執行6和7
6. 建一個或多個bean物件
7. 獲取ResultSet裡儲存的值,並封裝到bean物件中
8. 關閉連線
第1步的封裝以後講,這個可以算是另一個小專案了
第2、3步我們已經封裝好了,就是dbc
接下來就是封裝4、5、6、7
程式碼:
package com.tool; import com.bean.Employee; import com.util.ClassUtil; import com.util.ObjectUtil; import com.util.StringUtil; import java.io.IOException; import java.lang.reflect.Field; importjava.lang.reflect.InvocationTargetException; import java.sql.*; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * * @param <E> bean的型別 * 一個bean對應一個表,且bean的類名用駝峰式命名,表的命名用下劃線全小寫命名 * 這個類是一個抽象類,必須有子類繼承並且給定E的型別 */ public abstract classMapper<E> { private Connection connection; public Mapper(Connection connection) { this.connection = connection; } public Mapper(String dbcPropertiesPath) throws SQLException, IOException, ClassNotFoundException { this.connection = Dbc.getConnection(dbcPropertiesPath); } /** * 將value轉換成合適的型別插入到合適的位置 */ private void castToSuitType(PreparedStatement preparedStatement,int index, Object value) throws SQLException { Class<?> valueClass = value.getClass(); if (valueClass == String.class) { preparedStatement.setString(index, String.valueOf(value)); } else if(valueClass == Integer.class || valueClass == int.class) { preparedStatement.setInt(index,(Integer)value); } else if (valueClass == Float.class || valueClass == float.class) { preparedStatement.setFloat(index,(Float) value); } else if (valueClass == Double.class || valueClass == double.class) { preparedStatement.setDouble(index,(Double) value); } else if (valueClass == Short.class || valueClass == short.class) { preparedStatement.setShort(index,(Short)value); } else { preparedStatement.setString(index, String.valueOf(value)); } } private <T> T castToSuitType(ResultSet resultSet,int index, Class<T> fieldClass) throws SQLException { Object value; if (fieldClass == String.class) { value = resultSet.getString(index); } else if(fieldClass == Integer.class || fieldClass == int.class) { value = resultSet.getInt(index); } else if (fieldClass == Float.class || fieldClass == float.class) { value = resultSet.getFloat(index); } else if (fieldClass == Double.class || fieldClass == double.class) { value = resultSet.getDouble(index); } else if (fieldClass == Short.class || fieldClass == short.class) { value = resultSet.getShort(index); } else { value = resultSet.getString(index); } return (T)value; } /** * 首先,我們要獲取所有的類列 * 每一列對應bean的類的一個屬性 * 列名用全小寫下劃線式 * 屬性名用首字母小寫的駝峰式 * * 接下來我們需要幾個一個工具類來處理字串 * 當然,要用的工具類我都提前寫好了 */ /** * 獲取泛型E的Class物件,即bean的型別的Class物件 * @return */ public Class<E> getBeanClass() { return ClassUtil.getSuperClassGenricType(this.getClass()); } /** * 獲取表名 * @param */ public String getTableName() { Class<E> beanClass = getBeanClass(); String className = beanClass.getName(); className = className.substring(className.lastIndexOf(".") +1); String tableName = StringUtil.castCamelCaseToUnderline(className); //保險起見首字母轉下小寫 tableName = StringUtil.firstLetterToLowerCase(tableName); return tableName; } /** * 獲取列名 * @return */ public List<String> getColumnNames() { Class<E> beanClass = getBeanClass(); Field[] fields = beanClass.getDeclaredFields(); List<String> columnNames = new ArrayList<String>(fields.length); for (Field field : fields) { String columnName = StringUtil.castCamelCaseToUnderline(field.getName()); //保險起見首字母轉下小寫 columnName = StringUtil.firstLetterToLowerCase(columnName); columnNames.add(columnName); } return columnNames; } //接下來封裝增刪改查操作 public void insert(E e) throws SQLException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { //String sql = "insert into tbl_employee (id,last_name,email,gender,d_id) values (?,?,?,?,?)"; String sql = "insert into "; sql += getTableName() + " ("; List<String> columnNames = getColumnNames(); for (String columnName : columnNames) { sql += columnName + ","; } //刪除最後一個逗號 sql = StringUtil.deleteLastChildString(sql,1); sql += ") values ("; //說了含金量高的,索性寫複雜點 List<Object> valueList = ObjectUtil.getAllFieldValue(e); for (Object value : valueList) { //用?當佔位符 sql += "?,"; } //刪除最後一個逗號 sql = StringUtil.deleteLastChildString(sql,1); sql += ");"; PreparedStatement preparedStatement = connection.prepareStatement(sql); for (int i = 0; i < valueList.size(); i++) { //這個也是從1開始 castToSuitType(preparedStatement,i + 1,valueList.get(i)); } preparedStatement.executeUpdate(); //總算把insert寫完了,後面的都差不多,我快點寫,就不寫註釋了 } public void delete(int id) throws SQLException { //String sql = "delete from tbl_employee where id = ?"; String sql = "delete from "; sql += getTableName() + " "; sql += "where "; Class<E> beanClass = getBeanClass(); //注意,在寫bean類的時候必須將主鍵寫在最前面,否則,這個程式碼要寫的更加複雜,因為涉及到註解 String primaryKeyName = beanClass.getDeclaredFields()[0].getName(); sql += primaryKeyName + "= ?;"; PreparedStatement preparedStatement = connection.prepareStatement(sql); preparedStatement.setInt(1,id); preparedStatement.executeUpdate(); } public void update(E e) throws SQLException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { //String sql = "update tbl_employee set last_name = ?,email = ?,gender = ?, d_id = ? where id = ?"; String sql = "update " + getTableName() + " set "; List<String> columnNames = getColumnNames(); String primaryKeyName = columnNames.remove(0); for (String columnName : columnNames) { sql += columnName + "=?,"; } sql = StringUtil.deleteLastChildString(sql,1); sql += " where " + primaryKeyName + "=?"; PreparedStatement preparedStatement = connection.prepareStatement(sql); List<Object> valueList = ObjectUtil.getAllFieldValue(e); Object primaryKeyValue = valueList.remove(0); //主鍵被挪到了最後,在where那裡 valueList.add(primaryKeyValue); for (int i = 0; i < valueList.size(); i++) { castToSuitType(preparedStatement,i + 1,valueList.get(i)); } preparedStatement.executeUpdate(); } public E selectByPrimaryKey(Object primaryKey) throws SQLException, IllegalAccessException, InstantiationException, NoSuchMethodException, NoSuchFieldException, InvocationTargetException { Class<E> beanClass = getBeanClass(); //以前說過,java bean必須有空建構函式,其實就是為了方便通過反射構造物件 E e = null; //String sql = "select * from tbl_employee where id = ?"; String sql = "select "; List<String> columnNames = getColumnNames(); for (String columnName : columnNames) { sql += columnName + ","; } sql = StringUtil.deleteLastChildString(sql,1); sql += " from " + getTableName() + " where "; //獲取主鍵名稱 String primaryKeyName = beanClass.getDeclaredFields()[0].getName(); sql += primaryKeyName + "= ?;"; PreparedStatement preparedStatement = connection.prepareStatement(sql); castToSuitType(preparedStatement,1,primaryKey); ResultSet resultSet = preparedStatement.executeQuery(); if (resultSet.next()) { //查得到資料才new,否則返回null e = getBeanFromResultSet(resultSet, beanClass); } return e; } /** * * @param conditionMap 鍵是列名,值是要匹配的值 * @return */ public List<E> selectByExample(Map<String,Object> conditionMap) throws SQLException, IllegalAccessException, InstantiationException, NoSuchMethodException, NoSuchFieldException, InvocationTargetException { List<E> resultList = new ArrayList<E>(); int size = conditionMap.keySet().size(); String[] keyArr = new String[size]; Object[] valueArr = conditionMap.values().toArray(); conditionMap.keySet().toArray(keyArr); //String sql = "select * from tbl_employee where "; String sql = "select "; List<String> columnNames = getColumnNames(); for (String columnName : columnNames) { sql += columnName + ","; } sql = StringUtil.deleteLastChildString(sql,1); sql += " from " + getTableName() + " where "; for (int i = 0; i < size; i++) { sql += keyArr[i] + "=? and "; //and前後要加空格 } //末尾多了一個and,去掉 sql = sql.substring(0,sql.lastIndexOf("and") - 1); PreparedStatement preparedStatement = connection.prepareStatement(sql); for (int i = 0; i < valueArr.length; i++) { castToSuitType(preparedStatement,i + 1,valueArr[i]); } ResultSet resultSet = preparedStatement.executeQuery(); Class<E> beanClass = getBeanClass(); while (resultSet.next()) { E e = getBeanFromResultSet(resultSet, beanClass); resultList.add(e); } return resultList; } //提取點公共程式碼 public E getBeanFromResultSet(ResultSet resultSet,Class<E> beanClass) throws IllegalAccessException, InstantiationException, SQLException, NoSuchMethodException, NoSuchFieldException, InvocationTargetException { E e = beanClass.newInstance(); Field[] fields = beanClass.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { //列數從1開始 Object value = castToSuitType(resultSet, i + 1, fields[i].getType()); ObjectUtil.setFieldValue(e,fields[i],value); } return e; } }
使用:
public class EmployeeMapper extends Mapper<Employee> { public EmployeeMapper(Connection connection) { super(connection); } public EmployeeMapper(String dbcPropertiesPath) throws SQLException, IOException, ClassNotFoundException { super(dbcPropertiesPath); } }
測試:
public static void main(String[] args) throws Exception { //測一下,我也不確定我能不能一次寫對 EmployeeMapper mapper = new EmployeeMapper("src/com/resource/dbc.properties"); //通過 Employee employee = mapper.selectByPrimaryKey(3); System.out.println(employee); //通過 mapper.delete(100); //通過 employee = new Employee(13,"mahuateng","[email protected]","1",1004); mapper.update(employee); //通過 employee = new Employee(100,"xiaowang","[email protected]","0",1002); mapper.insert(employee); //通過 Map<String,Object > map = new HashMap<String, Object>(); map.put("gender","1"); map.put("d_id",1002); List<Employee> employees = mapper.selectByExample(map); for (Employee employee1 : employees) { System.out.println(employee1); } }
工具類:
package com.util; //字串工具類 //這個工具類裡的所有方法要求看懂並且可以自己寫出來 //這個裡的所有方法全是我自己手寫出來的,要求你們也要可以手寫出來 public class StringUtil { /** * 將字串首字母轉換成大寫 * * @param str 要轉換的字串 * @return 返回str首字母大寫後的字串 */ public static String firstLetterToUpperCase(String str) { //這裡只替換第一個 return str.replaceFirst(String.valueOf(str.charAt(0)),String.valueOf(str.charAt(0)).toUpperCase()); } /** * 將字串首字母轉換成小寫 * * @param str 要轉換的字串 * @return 返回str首字母瞎寫寫後的字串 */ public static String firstLetterToLowerCase(String str) { //這裡只替換第一個 return str.replaceFirst(String.valueOf(str.charAt(0)),String.valueOf(str.charAt(0)).toLowerCase()); } /** * 駝峰轉下劃線 * 解釋下什麼叫駝峰式,就是每個單詞的首字母大寫,其餘字母都小寫 * java推薦所有變數、方法、類都使用駝峰式命名 * 類名一般第一個單詞的首字母也要大寫 * 變數、方法第一個單詞的首字母小寫 * 下劃線式是指全字母小寫或全字母大寫,單詞之間用下劃線分割,如cast_camel_case_to_underline * 常量採用全字母大寫加下劃線式 */ /** * 將駝峰式字串轉換成下劃線式 * * @param str 駝峰式字串 * @return 下劃線式字串 */ public static String castCamelCaseToUnderline(String str) { char[] chars = str.toCharArray(); String result = ""; for (char i : chars) { if (i >= 'A' && i <= 'Z') { result += "_" + String.valueOf(i).toLowerCase(); } else { result += i; } } if (result.startsWith("_")) { result = result.substring(1); } return result; } /** * 將下劃線字串轉換成駝峰式 * * @param str 下劃線式字串 * @return 駝峰式字串 */ public static String castUnderlineToCamelCase(String str) { String[] split = str.split("_"); String result = ""; for (String s : split) { result += firstLetterToUpperCase(s); } return firstLetterToLowerCase(result); } /** * 刪除下劃線最後length位字元 * * @param str 要處理的字串 * @param length 要刪除字串最後多少位字元 * @return 刪除str字串最後length位字元後的新字串 */ public static String deleteLastChildString(String str,int length) { return str.substring(0,str.length() - length); } }
package com.util; import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; public class ObjectUtil { /** * 獲取object的屬性值 * @param object 要獲取屬性值的鍍錫 * @param fieldName 屬性名 * @return object的filedName對應的屬性值 */ public static Object getFieldValue(Object object,String fieldName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { String getterMethodName = "get" + StringUtil.firstLetterToUpperCase(fieldName); //只要public的getter方法 Method getterMethod = object.getClass().getMethod(getterMethodName); if (getterMethod != null) { Object value = getterMethod.invoke(object); return value; } return null; } /** * 獲取object的屬性值 * @param object 要獲取屬性值的鍍錫 * @param field 屬性 * @return object的filed對應的屬性值 */ public static Object getFieldValue(Object object,Field field) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { return getFieldValue(object,field.getName()); } /** * 獲取object的所有屬性值 * @param object 要獲取屬性值的鍍錫 * @return object的所有屬性值組成的List集合 */ public static List<Object> getAllFieldValue(Object object) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { Field[] declaredFields = object.getClass().getDeclaredFields(); List<Object> valueList = new ArrayList<Object>(declaredFields.length); for (Field field : declaredFields) { valueList.add(getFieldValue(object,field)); } return valueList; } /** * 設定object的屬性值 * @param object 要獲取屬性值的鍍錫 * @param fieldName 屬性名 * @param value 要設定的屬性值 * @return object的filedName對應的屬性值 */ public static void setFieldValue(Object object,String fieldName,Object value) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException { String setterMethodName = "set" + StringUtil.firstLetterToUpperCase(fieldName); Class<?> fieldClass = object.getClass().getDeclaredField(fieldName).getType(); //只要public的getter方法 Method setterMethod = object.getClass().getMethod(setterMethodName,fieldClass); if (setterMethod != null) { setterMethod.invoke(object,value); } } /** * 設定object的屬性值 * @param object 要獲取屬性值的鍍錫 * @param field 屬性 * @param value 要設定的屬性值 * @return object的filedName對應的屬性值 */ public static void setFieldValue(Object object, Field field, Object value) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException { setFieldValue(object,field.getName(),value); } }
package com.util; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; //這個工具類的所有方法會用就行,以後需要就直接複製貼上 //反正這個玩意我也是百度的 public class ClassUtil { /** * 獲取父類的泛型的型別 * @param clazz 子類 * @return 父類的泛型的Class物件 */ public static Class getSuperClassGenricType(Class clazz) { return getSuperClassGenricType(clazz, 0); } /** * 通過反射,獲得定義Class時宣告的父類的範型引數的型別. 如public BookManager extends GenricManager<Book> * * @param clazz clazz The class to introspect * @param index the Index of the generic ddeclaration,start from 0. */ public static Class getSuperClassGenricType(Class clazz, int index) throws IndexOutOfBoundsException { Type genType = clazz.getGenericSuperclass(); if (!(genType instanceof ParameterizedType)) { return Object.class; } Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); if (index >= params.length || index < 0) { return Object.class; } if (!(params[index] instanceof Class)) { return Object.class; } return (Class) params[index]; } }