隨着shh2各種操作方便框架。越來越多JAVA WEB效率,可是,假設在不了解這些框架使用的場合的情況下,一拿到項目就盲目地選擇這些框架進行系統架構的搭建,就有可能造成非常多不是必需的資源浪費。
在項目開發中。對數據庫的CRUD操作我們一般都是無法避免的操作,盡管hibernate封裝的非常完美,可是。因為本人對這個框架的底層原理不是非常了解,每次使用的時候心里總認為沒底。代碼一旦出現異常,非常多時候都沒法高速有效地解決。因此,為了讓代碼異常處理風險控制在自己的可控范圍內,還是決定先將數據的CRUD持久化操作(DAO)用自己的方式通過JDBC進行一次封裝,以便更好地管理自己的代碼。
關於Hibernate框架的使用,還是先弄懂它的一些底層實現原理后。再依據項目的須要酌情選擇使用。
以下詳細講講通過我自己的方式對有關DAO層數據庫基本CRUD操作的JAVA實現(此處已MySQL為例,其它數據庫僅僅需做部分改動就可以)。
備注:若要試用本演示樣例,僅僅需依照給出的順序依次復制代碼建立對應的類就可以。另外。在項目lib文件夾下增加mysql鏈接jar包。
(1)定義數據源常量類
package com.jkitn.jkits.common;
/**
* 定義數據源常量類
* @author xdweleven
* @version 1.0
*/
public class JdbcConfig {
/** 數據庫驅動 */
public static final String DRIVERCLASSNAME = "com.mysql.jdbc.Driver";
/** 數據庫URL */
public static final String URL = "jdbc:mysql://localhost:3306/app_jkit";
/** 數據庫username */
public static final String USERNAME = "root";
/** 數據庫password */
public static final String PASSWORD = "root";
}
(2)定義結果集(ResultSet)到pojo對象的映射
package com.jkitn.jkits.dao.common;
import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* 說明:實現結果集到pojo對象的映射
* @author xdweleven
* @version 1.0
*/
public class RowMapper<T>{
private Class<T> objectClass;
public RowMapper(Class<T> objectClass) {
this.objectClass = objectClass;
}
/**
* 實現單條記錄到對象的映射
* @param rs 結果集
* @param rowNum 當前行數
* @return
* @throws SQLException
*/
public T mapRow(ResultSet rs, int rowNum) throws SQLException {
try {
T object = objectClass.newInstance();
// 得到結果集的字段集合
ResultSetMetaData metaData = rs.getMetaData();
int columnNum = metaData.getColumnCount();
Field[] fields = object.getClass().getDeclaredFields();
// 設置對象屬性的值。若不存在。則設置為null.
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
int flag = 0;
for (int j = 1; j <= columnNum; j++) {
if (metaData.getColumnName(j).toLowerCase().equals(field.getName().toLowerCase())) {
flag = 1;
break;
}
}
field.setAccessible(true);
if (flag == 1) {
this.typeMapper(field, object, rs);
}else {
field.set(object, null);
}
field.setAccessible(false);
}
return object;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
/**
* 實現多條記錄到結果集的映射
* @param rs
* @return
*/
public List<T> mapRows(ResultSet rs){
int rowNum = 0;
List<T> objList = new ArrayList<T>();
try {
while(rs.next()){
objList.add(this.mapRow(rs, rowNum++));
}
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
return objList;
}
/**
* 類型的映射
* @param field
* @param obj
* @param rs
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @throws SQLException
*/
private void typeMapper(Field field, Object obj, ResultSet rs) {
String typeName = field.getType().getName(); // 得到字段類型
try {
if (typeName.equals("java.lang.String")) {
field.set(obj, rs.getString(field.getName()));
} else if (typeName.equals("int")
|| typeName.equals("java.lang.Integer")) {
field.set(obj, rs.getInt(field.getName()));
} else if (typeName.equals("long")
|| typeName.equals("java.lang.Long")) {
field.set(obj, rs.getLong(field.getName()));
} else if (typeName.equals("float")
|| typeName.equals("java.lang.Float")) {
field.set(obj, rs.getFloat(field.getName()));
} else if (typeName.equals("double")
|| typeName.equals("java.lang.Double")) {
field.set(obj, rs.getDouble(field.getName()));
} else if (typeName.equals("boolean")
|| typeName.equals("java.lang.Boolean")) {
field.set(obj, rs.getBoolean(field.getName()));
} else if (typeName.equals("java.util.Date")) {
field.set(obj, rs.getTimestamp(field.getName()));
} else {
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
(3)定義數據庫連接輔助類DBConn
package com.jkitn.jkits.common;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import com.jkitn.jkits.dao.common.RowMapper;
/**
* 定義數據庫連接輔助類DBConn
* @author xdweleven
* @version 1.0
*/
public class DBConn {
private Connection conn = null;
private PreparedStatement pstmt = null;
private ResultSet rs = null;
/**
* 創建數據庫的連接
* @return 返回數據庫連接對象
*/
public Connection getConn(){
try {
// 載入數據庫驅動
Class.forName(JdbcConfig.DRIVERCLASSNAME);
// 創建Connection接口對象。用於獲取MySQL數據庫的連接對象
conn = DriverManager.getConnection(JdbcConfig.URL, JdbcConfig.USERNAME, JdbcConfig.PASSWORD);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
/**
* 更新數據庫操作(包含增刪改操作)
* @param sql 待運行sql語句
* @param objs 用於設置預編譯語句中帶入的參數
* @return null
* @throws Exception
*/
public int execUpdate(String sql, Object ...objs) throws Exception{
// 獲取預編譯環境
pstmt = this.getConn().prepareStatement(sql);
if(objs != null && objs.length > 0){
for(int i = 0; i < objs.length; i++){
pstmt.setObject(i+1, objs[i]);
}
}
// 運行更新語句
int result = pstmt.executeUpdate();
// 斷開連接。釋放資源
this.close(rs, pstmt, conn);
return result;
}
/**
* 數據庫查詢操作
* @param sql 待運行sql語句
* @param objs 用於設置預編譯語句中帶入的參數
* @return 類T的List數據類型,即返回查詢到的全部數據信息
* @throws Exception
*/
public <T> List<T> execQuery(String sql, RowMapper<T> mapper, Object ...objs) throws Exception{
// 獲取預編譯環境
pstmt = this.getConn().prepareStatement(sql);
if(objs != null && objs.length > 0){
for(int i = 0; i < objs.length; i++){
pstmt.setObject(i+1, objs[i]);
}
}
// 運行更新語句
rs = pstmt.executeQuery();
// 運行關系到對象的映射
List<T> result = mapper.mapRows(rs);
// 斷開連接。釋放資源
this.close(rs, pstmt, conn);
return result;
}
/**
* 運行運行的SQL語句並返回結果集
* @param sql SQL語句
* @param params 參數
* @return 返回結果集
*/
public ResultSet queryForResultSet(String sql, Object... objs) throws Exception{
// 獲取預編譯環境
pstmt = conn.prepareStatement(sql);
if(objs != null && objs.length > 0){
for(int i = 0; i < objs.length; i++){
pstmt.setObject(i+1, objs[i]);
}
}
// 運行更新語句
rs = pstmt.executeQuery();
// 斷開連接,釋放資源
this.close(null, pstmt, conn);
return rs;
}
/**
* 關閉數據庫連接,釋放所占的系統資源
* @param rs結果集、ppst預編譯命令、conn數據庫
* @return null
* @throws Exception
*/
public void close(ResultSet rs, PreparedStatement ppst, Connection conn) throws Exception{
if(rs != null){
rs.close();
}
if(ppst != null){
ppst.close();
}
if(conn != null){
conn.close();
}
}
}
(4)定義通用分頁查詢實體類
package com.jkitn.jkits.common;
import java.util.List;
/**
* 說明:實現通用分頁查詢實體類
* @author xdweleven
* @version 1.0
*/
public class PageBean<T> {
private int totalRows; // 總記錄數
private int totalPages; // 總頁數
private int curPage; // 當前頁碼
private int prePage; // 上一頁頁碼
private int nextPage; // 下一頁頁碼
private int rowsPerPage; // 每頁顯示的記錄數
private List<T> pageList; // 當前頁的數據集
/**
* 初始化分頁bean對象
* @param totalRows 總記錄數
* @param rowsPerPage 每頁顯示的記錄數
*/
public void initPageBean(int totalRows, int rowsPerPage){
this.rowsPerPage = rowsPerPage;
this.totalRows = totalRows;
this.totalPages = (this.totalRows-1)/this.rowsPerPage + 1;
// 設置上一頁
if(this.curPage == 1){
this.setPrePage(1);
}else{
this.setPrePage(this.curPage-1);
}
// 設置下一頁
if(this.curPage == this.totalPages){
this.setNextPage(this.totalPages);
}else{
this.setNextPage(this.curPage + 1);
}
}
/**
* 生成SQLServer的分頁查詢語句
* @param sql 原始sql語句
* @param curPage 第幾頁
* @param rowsPerPage 每頁多少行
*/
public String getPageSQLServer(String sql, int curPage, int rowsPerPage){
String afterFrom = sql.toLowerCase().substring(sql.indexOf("from"));
String pageSql = null;
if(afterFrom.indexOf("where") == -1){
pageSql = "select top "+ rowsPerPage + " * "+afterFrom
+" where id not in(select top "+rowsPerPage*(curPage-1)+" id "
+afterFrom+" order by id desc)"+"order by id desc";
}else{
pageSql = "select top "+ rowsPerPage + " * "+afterFrom
+" and id not in(select top "+rowsPerPage*(curPage-1)+" id "
+afterFrom+" order by id desc)"+"order by id desc";
}
return pageSql;
}
/**
* 生成MySql分頁sql語句
* @param sql 原始sql語句
* @param curPage 第幾頁
* @param rowsPerPage 每頁多少行
* @return 返回分頁SQL語句
*/
public String getPageMySQL(String sql, int curPage, int rowsPerPage){
String pageSql = sql+" limit "+ (curPage-1)*rowsPerPage+","+rowsPerPage;
return pageSql;
}
/**
* 生成Oracle分頁查詢語句
* @param sql 原始sql語句
* @return 返回分頁SQL語句
*/
public String getOrclPageSql(String sql){
int begin = (curPage - 1) * rowsPerPage;
int end = begin + rowsPerPage;
StringBuffer pagingSelect = new StringBuffer(300);
pagingSelect.append("select * from ( select row_.*, rownum rownum_ from ( ");
pagingSelect.append(sql);
pagingSelect.append(" ) row_ where rownum <= "+end+") where rownum_ > "+begin);
return pagingSelect.toString();
}
public List<T> getPageList() {
return pageList;
}
public void setPageList(List<T> pageList) {
this.pageList = pageList;
}
public int getTotalRows() {
return totalRows;
}
public void setTotalRows(int totalRows) {
this.totalRows = totalRows;
}
public int getTotalPages() {
return totalPages;
}
public void setTotalPages(int totalPages) {
this.totalPages = totalPages;
}
public int getCurPage() {
return curPage;
}
public void setCurPage(int curPage) {
this.curPage = curPage;
}
public int getPrePage() {
return prePage;
}
public void setPrePage(int prePage) {
this.prePage = prePage;
}
public int getNextPage() {
return nextPage;
}
public void setNextPage(int nextPage) {
this.nextPage = nextPage;
}
public int getRowsPerPage() {
return rowsPerPage;
}
public void setRowsPerPage(int rowsPerPage) {
this.rowsPerPage = rowsPerPage;
}
}
(5)定義SQL語句的經常用法工具類
package com.jkitn.jkits.util;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 說明:自己主動生成對象的增刪改查SQL語句的通用方法工具類
* @author xdweleven
* @version 1.0
*/
public class SQLUtil {
/**
* 自己主動生成插入指定對象的SQL語句,不包括對象屬性的值為空的字段
* @param obj 待生成插入SQL語句的對象
* @param tableName 待插入語句相應的數據庫表的名稱
* @return 返回一個包括SQL語句、SQL語句參數值及參數值類型的Map對象
*/
public static Map<String, Object> generateInsertExceptNull(Object obj, String tableName) {
StringBuffer columnStrBuf = new StringBuffer(); // 記錄數據表的字段名稱
StringBuffer paramStrBuf = new StringBuffer(); // 記錄SQL語句相應插入的占位符
List<Object> paramValues = new ArrayList<Object>(); // 記錄對象參數值
List<Integer> paramsType = new ArrayList<Integer>(); // 記錄參數值類型
// 查詢待插入對象的屬性值不為空的屬性名稱
List<Object> fieldList = ReflectionUtil.getNotNullField(obj);
try {
for (int i = 0; i < fieldList.size(); i++) {
Field field = (Field) fieldList.get(i);
field.setAccessible(true);
// 記錄對象屬性名稱
columnStrBuf.append(field.getName());
if (i != fieldList.size() - 1) {
columnStrBuf.append(",");
}
// 記錄插入SQL語句的參數占位符
if("class java.util.Date".equals(field.getType().toString())
&& field.get(obj) != null){
String timeStr = DateUtil.formatDate((Date)field.get(obj), "yyyy-MM-dd HH:mm:ss");
paramStrBuf.append("to_date(?, 'yyyy-MM-dd HH24:mi:ss')");
paramValues.add(timeStr);
// 記錄對象屬性的數據類型
paramsType.add(getOrclDataType(field.getType().toString()));
}else{
paramStrBuf.append("?");
paramValues.add(field.get(obj));
// 記錄對象屬性的數據類型
paramsType.add(getOrclDataType(field.getType().toString()));
}
if (i != fieldList.size() - 1) {
paramStrBuf.append(",");
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
// 生成插入操作的SQL語句
StringBuffer sb = new StringBuffer();
sb.append("insert into ");
sb.append(tableName);
sb.append(" (");
sb.append(columnStrBuf);
sb.append(") ");
sb.append("values");
sb.append(" (");
sb.append(paramStrBuf);
sb.append(")");
// 將生成的SQL語句、SQL語句參數值及各參數值的數據類型用map保存並返回
Map<String, Object> sqlMap = new HashMap<String, Object>();
sqlMap.put("sql", sb.toString());
sqlMap.put("paramsValues", paramValues.toArray());
sqlMap.put("paramsTypes", paramsType.toArray());
return sqlMap;
}
/**
* 自己主動生成插入指定對象的SQL語句,包括對象屬性的值為空的字段,不包括自增長主鍵,若不存在,調用時直接置為null.
* @param obj 待生成插入SQL語句的對象
* @param tableName 待插入語句相應的數據庫表的名稱
* @param keyColumn 數據表主鍵名稱
* @return 返回一個包括SQL語句、SQL語句參數值及參數值類型的Map對象
* @throws IllegalAccessException
* @throws IllegalArgumentException
*/
public static Map<String, Object> generateInsertWithNull(Object obj,
String tableName, String keyColumn) throws IllegalArgumentException, IllegalAccessException {
StringBuffer columnStrBuf = new StringBuffer();
StringBuffer paramStrBuf = new StringBuffer(); // 記錄SQL語句相應插入的占位符
List<Object> columnNameList = new ArrayList<Object>(); // 記錄數據表的字段名稱
List<Object> paramValues = new ArrayList<Object>(); // 記錄對象參數值
List<Integer> paramsType = new ArrayList<Integer>(); // 記錄參數值類型
Field[] fields = obj.getClass().getDeclaredFields();
for(int i = 0; i < fields.length; i++){
fields[i].setAccessible(true);
// 記錄對象屬性名稱
if(!fields[i].getName().equalsIgnoreCase(keyColumn)){ // 非主鍵列記錄插入SQL語句的參數占位符
columnStrBuf.append(fields[i].getName());
columnNameList.add(fields[i].getName());
if (i != fields.length - 1) {
columnStrBuf.append(",");
}
if("class java.util.Date".equals(fields[i].getType().toString())
&& fields[i].get(obj) != null){
String timeStr = DateUtil.formatDate((Date)fields[i].get(obj), "yyyy-MM-dd HH:mm:ss");
paramStrBuf.append("to_date(?, 'yyyy-MM-dd HH24:mi:ss')");
paramValues.add(timeStr);
// 記錄對象屬性的數據類型
paramsType.add(getOrclDataType(fields[i].getType().toString()));
}else{
paramStrBuf.append("?");
paramValues.add(fields[i].get(obj));
// 記錄對象屬性的數據類型
paramsType.add(getOrclDataType(fields[i].getType().toString()));
}
if (i != fields.length - 1) {
paramStrBuf.append(",");
}
}
}
// 生成插入操作的SQL語句
StringBuffer sb = new StringBuffer();
sb.append("insert into ");
sb.append(tableName);
sb.append(" (");
sb.append(columnStrBuf);
sb.append(") ");
sb.append("values");
sb.append(" (");
sb.append(paramStrBuf);
sb.append(")");
// 將生成的SQL語句、SQL語句的列名稱用map保存並返回
Map<String, Object> sqlMap = new HashMap<String, Object>();
/*
System.out.println(sb.toString());
System.out.println(columnNameList.toString());
System.out.println(paramValues.toString());
System.out.println(paramsType.toString());
*/
sqlMap.put("sql", sb.toString());
sqlMap.put("columnNameList", columnNameList.toArray());
sqlMap.put("paramsValues", paramValues.toArray());
sqlMap.put("paramsTypes", paramsType.toArray());
return sqlMap;
}
/**
* 自己主動生成更新指定對象的SQL語句
* @param obj 待生成更新SQL語句的對象
* @param tableName 待更新語句相應的數據庫表的名稱
* @param keyColumn 待更新記錄的限定字段
* @return 返回一個包括SQL語句及參數值的數組
*/
public static Object[] generateUpdate(Object obj, String tableName, String keyColumn) {
StringBuffer columnSB = new StringBuffer();
List<Object> params = new ArrayList<Object>();
Object keyValue = null;
// 獲取屬性值不為空的數據表字段名稱
List<Object> fieldList = ReflectionUtil.getNotNullField(obj);
try {
for (int i = 0; i < fieldList.size(); i++) {
Field field = (Field) fieldList.get(i);
field.setAccessible(true);
if (field.getName().equalsIgnoreCase(keyColumn)) {
keyValue = field.get(obj);
} else {
columnSB.append(field.getName());
if("class java.util.Date".equals(field.getType().toString())
&& field.get(obj) != null){
String timeStr = DateUtil.formatDate((Date)field.get(obj), "yyyy-MM-dd HH:mm:ss");
columnSB.append("=to_date(?, 'yyyy-MM-dd HH24:mi:ss')");
params.add(timeStr);
}else{
columnSB.append("=?");
params.add(field.get(obj));
}
if (i != fieldList.size() - 1) {
columnSB.append(",");
}
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
if (keyValue == null) {
throw new IllegalArgumentException("數據表 [" + tableName+ "] 中的字段'"+keyColumn+"'的值不能為空.");
}else{
params.add(keyValue);
}
StringBuffer sb = new StringBuffer();
sb.append("update ");
sb.append(tableName);
sb.append(" set ");
if(columnSB.length() >= 0){
sb.append(columnSB);
}else{
sb.append(keyColumn);
sb.append("=? ");
params.add(keyValue);
}
sb.append(" where ");
sb.append(keyColumn);
sb.append("=?
");
return new Object[] { sb.toString(), params.toArray() };
}
/**
* 返回java數據類型相應的Oracle數據庫的數據類型值
* @param javaType java數據類型
* @return 返回Oracle數據表的字段數據類型
*/
public static int getOrclDataType(String javaType){
if("class java.lang.String".equals(javaType)){
return java.sql.Types.VARCHAR;
}else if("class java.lang.Integer".equals(javaType) || "int".equals(javaType)){
return java.sql.Types.INTEGER;
}else if("class java.lang.Double".equals(javaType) || "double".equals(javaType)){
return java.sql.Types.DOUBLE;
}else if("class java.lang.Float".equals(javaType) || "float".equals(javaType)){
return java.sql.Types.FLOAT;
}else if("char".equals(javaType)){
return java.sql.Types.CHAR;
}else if("class java.lang.Long".equals(javaType) || "long".equals(javaType)){
return java.sql.Types.NUMERIC;
}else if("class java.util.Date".equals(javaType)){
return java.sql.Types.DATE;
}else{
return java.sql.Types.VARCHAR;
}
}
/**
* 生成SQL語句中的where子句及where子句中參數值
* @param obj where條件子句的對象
* @return 返回條件不為空的where子句
* @throws Exception
* @throws
*/
public static Map<String, Object> generateWhereStr(Object obj) throws Exception{
StringBuffer whereStrBuf = new StringBuffer(); // where子句
List<Object> whereParamValues = new ArrayList<Object>(); // where子句中的參數值
whereStrBuf.append(" where 1 = 1 ");
if(obj != null){
Field[] fields = obj.getClass().getDeclaredFields();
for(int i = 0; i < fields.length; i++){
fields[i].setAccessible(true);
Object columnName = fields[i].get(obj);
if(columnName != null && !"".equals(columnName)){
whereStrBuf.append(" and ");
whereStrBuf.append(fields[i].getName());
whereStrBuf.append("=?");
whereParamValues.add(columnName);
}
}
}
Map<String, Object> whereMap = new HashMap<String, Object>();
/* System.out.println(whereStrBuf.toString());
System.out.println(whereParamValues);
*/
whereMap.put("whereStr", whereStrBuf.toString());
whereMap.put("whereParamValues", whereParamValues.toArray());
return whereMap;
}
}
(6)擴展JAVA對象的反射工具類
package com.jkitn.jkits.util;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* 說明:擴展JAVA對象的反射機制
* @author xdweleven
* @version 1.0
*/
public class ReflectionUtil {
/**
* 設置對象的指定屬性名稱的屬性值
* @param obj 待設置的對象
* @param fieldName 對象屬性名稱
* @param value 屬性值
*/
public static void setFieldValue(Object obj, String fieldName, Object value) {
Class<? extends Object> c = obj.getClass();
try {
Field field = null;
Field[] fields = c.getDeclaredFields();
for(int i = 0; i < fields.length; i++){
String fieldNameTemp = fields[i].getName();
if(fieldNameTemp.equalsIgnoreCase(fieldName)){
field = c.getDeclaredField(fieldNameTemp);
field.setAccessible(true);
field.set(obj, value);
return;
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 獲取對象的指定屬性名稱的屬性值
* @param obj 待設置的對象
* @param fieldName 對象屬性名稱
*/
public static Object getFieldValue(Object obj, String fieldName) {
Class<? extends Object> c = obj.getClass();
Field[] fields = c.getDeclaredFields();
try {
for(int i = 0; i < fields.length; i++){
if(fields[i].getName().equalsIgnoreCase(fieldName)){
fields[i].setAccessible(true);
return fields[i].get(obj);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return null;
}
/**
* 獲取對象的屬性值不為空的屬性名稱
* @param obj 待獲取的對象
* @return 返回屬性值不為空的對象的屬性名稱列表
*/
public static List<Object> getNotNullField(Object obj) {
Class<? extends Object> c = obj.getClass();
List<Object> list = new ArrayList<Object>();
try {
Field[] fields = c.getDeclaredFields();
for(int i = 0; i < fields.length; i++){
fields[i].setAccessible(true);
if(fields[i].get(obj) != null){
list.add(fields[i]);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return list;
}
}
(7)定義實現數據庫的CRUD基本操作BaseDao
package com.jkitn.jkits.dao.common;
import java.io.Serializable;
import java.sql.ResultSet;
import java.util.List;
import java.util.Map;
import com.jkitn.jkits.common.DBConn;
import com.jkitn.jkits.common.PageBean;
import com.jkitn.jkits.util.ReflectionUtil;
import com.jkitn.jkits.util.SQLUtil;
/**
* 說明:封裝實現數據庫的CRUD相關的底層操作。
* @author xdweleven
* @version 1.0
*/
public class BaseDao{
// 獲取數據庫鏈接實例
private DBConn dbconn = new DBConn();
/** 數據庫表的前綴 */
public static final String TB_PREFIX = "tb_jkit_";
/** 數據庫表的查詢前綴 */
public static final String SELECT_TB_PREFIX = "select * from tb_jkit_";
/** 升序排列 */
public static final String ASC = "asc";
/** 降序排列 */
public static final String DESC = "desc";
/**
* 依據ID查找對象
* @param classType 對象類型
* @param columnName 編號字段名稱
* @param id 對象編號
* @return 返回實體對象
*/
public <T> T queryById(Class<T> classType, String columnName, Serializable id)
throws Exception{
StringBuffer sqlBuffer = new StringBuffer();
sqlBuffer.append(SELECT_TB_PREFIX);
sqlBuffer.append(this.toLowerCaseFirstOne(classType.getSimpleName()));
sqlBuffer.append(" where ");
sqlBuffer.append(columnName);
sqlBuffer.append(" = ? ");
this.showSQL(sqlBuffer.toString());
return dbconn.execQuery(sqlBuffer.toString(), new RowMapper<T>(classType),
new Object[]{id}).get(0);
}
/**
* 查詢全部指定class類型的對象信息
* @param classType 對象類型
* @return 返回實體對象列表
*/
public <T> List<T> queryAll(Class<T> classType) throws Exception{
String sql = SELECT_TB_PREFIX + this.toLowerCaseFirstOne(classType.getSimpleName());
this.showSQL(sql);
return dbconn.execQuery(sql, new RowMapper<T>(classType));
}
/**
* 查詢指定對象類型的對象信息,並依照指定的排序字段進行升序或降序排序
* @param classType 對象類型
* @param orderColumn 排序字段
* @param ascOrDesc 降序或升序:asc表示升序。desc表示降序
* @return 返回實體對象列表
*/
public <T> List<T> queryAllWithOrder(Class<T> classType, String orderColumn,
String ascOrDesc) throws Exception{
StringBuffer sqlBuffer = new StringBuffer();
sqlBuffer.append(SELECT_TB_PREFIX);
sqlBuffer.append(this.toLowerCaseFirstOne(classType.getSimpleName()));
sqlBuffer.append(" order by ");
sqlBuffer.append(orderColumn);
sqlBuffer.append(" ");
sqlBuffer.append(ascOrDesc);
this.showSQL(sqlBuffer.toString());
return dbconn.execQuery(sqlBuffer.toString(), new RowMapper<T>(classType));
}
/**
* 查詢指定SQL語句的對象信息列表
* @param sql 查詢語句
* @param classType 對象類型
* @param params SQL語句參數
* @return 返回實體對象列表
*/
public <T> List<T> query(String sql, Class<T> classType, Object... params)
throws Exception{
this.showSQL(sql);
return dbconn.execQuery(sql, new RowMapper<T>(classType), params);
}
/**
* 查詢指定SQL語句的對象信息列表
* @param sql 查詢語句
* @param classType 對象類型
* @param params SQL語句參數
* @return 返回實體對象列表
*/
public <T> T queryForObj(String sql, Class<T> classType, Object... params)
throws Exception{
this.showSQL(sql);
return dbconn.execQuery(sql, new RowMapper<T>(classType), params).get(0);
}
/**
* 分頁查詢實體對象列表信息
* @param sql 原始的SQL語句
* @param classType 對象類型
* @param curPage 當前頁碼
* @param rowsPerPage 每頁顯示的記錄數
* @param params SQL語句參數
* @return 返回當前頁碼的分頁對象
*/
public <T> PageBean<T> queryByPage(String sql, Class<T> classType, int curPage,
int rowsPerPage, Object... params) throws Exception{
// 獲取記錄總數
int totalRows = this.getTotalRows(sql, params);
PageBean<T> pageBean = new PageBean<T>();
pageBean.setCurPage(curPage); // 設置當前頁碼
pageBean.initPageBean(totalRows, rowsPerPage); // 初始化分頁對象的相關屬性
// 生成當前分頁查詢語句(MySql)
String pageSql = pageBean.getPageMySQL(sql, curPage, rowsPerPage);
this.showSQL(pageSql);
// 運行查詢操作
pageBean.setPageList(dbconn.execQuery(sql, new RowMapper<T>(classType), params));
return pageBean;
}
/**
* 保存對象到數據庫中,若數據庫中的用戶表有自增序列,則須要指出表中自增列的字段名稱,另外,
* 數據庫中相應的自增序列的名稱需按例如以下格式取名:class名稱_自增列字段名稱_SEQ,
* 比如用戶的class為Users,自增序列字段名稱為id,則數據庫中的自增序列的名稱取名為USERS_ID_SEQ.
* @param obj 實體對象
* @param sequenceKeyColumn 數據表自增序列的字段名稱,若不存在。則置為null。
* @return 返回被更新的記錄數
* @throws IllegalAccessException
* @throws IllegalArgumentException
*/
public <T> int insert(T obj, String sequenceKeyColumn) throws Exception{
String tableName = TB_PREFIX + this.toLowerCaseFirstOne(obj.getClass().getSimpleName());
// 自己主動生成對象的無自增序列插入SQL語句及其相關插入的參數值和類型
Map<String, Object> sqlMap = SQLUtil.generateInsertWithNull(obj, tableName, sequenceKeyColumn);
String sql = sqlMap.get("sql").toString(); // SQL語句
Object[] paramsValues = (Object[])sqlMap.get("paramsValues"); // SQL語句的參數值
// int[] paramsTypes = this.parseArrayToInt((Object[])sqlMap.get("paramsTypes")); // 參數值類型
this.showSQL(sql);
return dbconn.execUpdate(sql, paramsValues);
}
/**
* 更新對象
* @param obj 待更新的實體對象
* @param keyColumn 更新對象的限定條件字段名稱
* @return 返回被更新的記錄數
*/
public <T> int update(T obj, String keyColumn) throws Exception{
String tableName = TB_PREFIX + this.toLowerCaseFirstOne(obj.getClass().getSimpleName());
// 自己主動生成對象的更新操作的SQL語句及其參數值
Object[] updateSql = SQLUtil.generateUpdate(obj, tableName, keyColumn);
this.showSQL(updateSql[0].toString());
return dbconn.execUpdate(updateSql[0].toString(), (Object[])updateSql[1]);
}
/**
* 刪除對象
* @param obj 待更新的實體對象
* @param keyColumn 刪除的限定條件字段
* @return 返回被刪除的記錄數
*/
public <T> int delete(T obj, String keyColumn) throws Exception{
// 獲取限定條件的值
Object keyValue = ReflectionUtil.getFieldValue(obj, keyColumn);
if(keyValue == null){
throw new RuntimeException("["+obj.getClass()+"]中不存在屬性'"+keyColumn+"'或屬性值為空.");
}
StringBuffer sqlBuffer = new StringBuffer();
sqlBuffer.append("delete from ");
sqlBuffer.append(TB_PREFIX);
sqlBuffer.append(this.toLowerCaseFirstOne(obj.getClass().getSimpleName()));
sqlBuffer.append(" where ");
sqlBuffer.append(keyColumn);
sqlBuffer.append(" = ? ");
this.showSQL(sqlBuffer.toString());
return dbconn.execUpdate(sqlBuffer.toString(), keyValue.toString());
}
/**
* 刪除指定編號的實體對象
* @param classType 對象類型
* @param keyColumn ID相應的數據表列名稱
* @param id 實體對象編號
* @return 返回刪除的記錄數
*/
public <T> int deleteById(Class<T> classType, String keyColumn, Serializable id)
throws Exception{
StringBuffer sqlBuffer = new StringBuffer();
sqlBuffer.append("delete from ");
sqlBuffer.append(TB_PREFIX);
sqlBuffer.append(this.toLowerCaseFirstOne(classType.getSimpleName()));
sqlBuffer.append(" where ");
sqlBuffer.append(keyColumn);
sqlBuffer.append(" = ? ");
this.showSQL(sqlBuffer.toString());
return dbconn.execUpdate(sqlBuffer.toString(), id);
}
/**
* 批量刪除指定編號的實體對象
* @param classType 對象類型
* @param idColumnName 編號字段名稱
* @param ids 待刪除對象的編號數組
*/
public <T> int deleteByIds(Class<T> classType, String idColumnName,
Serializable[] ids) throws Exception{
StringBuffer sqlBuffer = new StringBuffer();
sqlBuffer.append("delete from ");
sqlBuffer.append(TB_PREFIX);
sqlBuffer.append(this.toLowerCaseFirstOne(classType.getSimpleName()));
sqlBuffer.append(" where ");
sqlBuffer.append(idColumnName);
sqlBuffer.append(" = ? ");
this.showSQL(sqlBuffer.toString());
int rowNums = 0; // 刪除的記錄數
for(int i = 0; i < ids.length; i++){
rowNums += this.deleteById(classType, idColumnName, ids[i]);
}
return rowNums;
}
/**
* 更新操作
* @param sql 刪除操作的SQL語句
* @param params SQL語句中的參數值
* @return 返回刪除的記錄數
*/
public int update(String sql, Object... params) throws Exception{
this.showSQL(sql);
return dbconn.execUpdate(sql, params);
}
/**
* 批量更新對象
* @param objs 待更新的實體對象列表
* @param keyColumn 主鍵字段名稱
*/
public <T> int batchUpdate(List<T> objs, String keyColumn) throws Exception{
if(objs == null || objs.isEmpty()){
return 0;
}
int updateNum = 0;
// 自己主動生成對象的更新操作的SQL語句及其參數值
for(int i = 0; i < objs.size(); i++){
T obj = objs.get(i);
updateNum += this.update(obj, keyColumn);
}
return updateNum;
}
/**
* 批量插入對象
* @param objs 待新增的實體對象列表
* @param keyColumn 數據表主鍵列名稱
* @throws IllegalAccessException
* @throws IllegalArgumentException
*/
public <T> int batchInsert(List<T> objs, String keyColumn) throws Exception {
if(objs == null || objs.isEmpty()){
return 0;
}
int updateNum = 0;
// 自己主動生成對象的更新操作的SQL語句及其參數值
for(int i = 0; i < objs.size(); i++){
T obj = objs.get(i);
updateNum += this.insert(obj, keyColumn);
}
return updateNum;
}
/**
* 統計指定統計數量的SQL語句
* @param sql 待運行的SQL語句
* @param params SQL語句參數值
* @return 返回記錄總數
* @throws Exception
*/
public int getTotalRows(String sql, Object... params) throws Exception{
String totalRowsSql = "select count(*) totalRows from ( "+sql+" )";
this.showSQL(totalRowsSql);
ResultSet rs = dbconn.queryForResultSet(totalRowsSql, params);
while(rs.next()){
return rs.getInt("totalRows");
}
return 0;
}
/**
* 刪除操作
* @param sql 刪除操作的SQL語句
* @param params SQL語句中的參數值
* @return 返回刪除的記錄數
*/
public int delete(String sql, Object... params) throws Exception{
this.showSQL(sql);
return dbconn.execUpdate(sql, params);
}
/**
* 獲取下一個指定自增序列的值(MySql)
* @param classType 對象類型
* @param seqColName 自增字段名稱
* @return 返回指定表的主鍵自增序列的最新值
*/
public <T> int getNextAutoIncrementVal(Class<T> classType, String seqColName) throws Exception{
StringBuffer sqlBuf = new StringBuffer();
sqlBuf.append("select max(");
sqlBuf.append(seqColName);
sqlBuf.append(")+1 nextId from ");
sqlBuf.append(TB_PREFIX);
sqlBuf.append(this.toLowerCaseFirstOne(classType.getSimpleName()));
this.showSQL(sqlBuf.toString());
ResultSet rs = dbconn.queryForResultSet(sqlBuf.toString());
if(rs.next()){
return rs.getInt("nextId");
}else{
return 0;
}
}
/**
* 首字母轉小寫
* @param str 待轉換的字符創
* @return 返回首字母小寫后的字符串
*/
public String toLowerCaseFirstOne(String str){
if(Character.isLowerCase(str.charAt(0))){
return str;
}else{
return (new StringBuilder()).append(Character.toLowerCase(str.charAt(0))).
append(str.substring(1)).toString();
}
}
/**
* 首字母轉大寫
* @param str 待轉換的字符串
* @return 返回首字母大寫的字符串
*/
public String toUpperCaseFirstOne(String str){
if(Character.isUpperCase(str.charAt(0))){
return str;
}else{
return (new StringBuilder()).append(Character.toUpperCase(str.charAt(0))).
append(str.substring(1)).toString();
}
}
/**
* 打印SQL語句
* @param sql
*/
public void showSQL(String sql){
System.out.println(sql);
}
}
以上是依據自己的理解封裝的一些經常使用DAO層操作,並已運用到部署上線的兩個項目中,眼下尚未報出BUG。
但在效率方面,個人認為還有非常多地方須要優化的地方。比方說批量增刪改操作。依據我個人PC機測試的結果,使用JDBC自帶的批量操作。要比上述簡單循環的操作速度要慢,但我還是認為這部分的效率還有非常大的提升空間,希望能有位IT大卡給我指點一二,不勝感激!
版權聲明:本文博客原創文章,博客,未經同意,不得轉載。
