新公司的ORM框架使用了hibernate,但是我並不會,剛來項目老闆催的緊,而且項目還是我獨立開發,所以就自己用JDBC完成功能,但是你懂的,jdbc代碼的冗餘,操作的複雜都是我們初學就很煩的事兒了,所以花了半天時間寫了一個BaseDao出來,代碼如下:
import java.lang.reflect.ParameterizedType;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.uqiauto.util.ConnectionUtils;
/**
* dao層父類
* 封裝了大部分的增刪改查代碼,但是關鍵實現都設置爲抽象,繼承此類需要提供具體實現
* 因爲父類try了SQLException,如果聲明其他異常可能會導致程序終止
* 所以如果需要限制訪問權限,可以在子類實現中聲明SQLException或其子類異常
* 例:限制用戶添加 throw new SQLException("This table is not allowed to be added");
*/
public abstract class BaseDao<T>{
private final Class<T> entityClass;
private final String entityClassName;
@SuppressWarnings("unchecked")
public BaseDao() {
// 通過範型反射,獲取在子類中定義的entityClass.
this.entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
entityClassName = entityClass.getSimpleName();
}
/**
* 獲取實體類對象
*/
public Class<T> getEntityClass() {
return entityClass;
}
/**
* 獲取實體類名(不包括包結構)
*/
public String getEntityClassName() {
return entityClassName;
}
/**
* 調用子類方法的入口,子類中只需要提供toObject方法的實現
* 查詢無參實現
* @param sql
* @param values
* @return
*/
public T queryOne(String sql){
T data = null;
try {
data = this.entityClass.newInstance();
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
Connection conn = ConnectionUtils.getConnection();
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
toObject(rs, data);
} catch (SQLException e) {
e.printStackTrace();
}finally {
ConnectionUtils.closeAll(rs, pstmt, Boolean.TRUE);
}
} catch (InstantiationException | IllegalAccessException e1) {
e1.printStackTrace();
}
return data;
}
/**
* 由子類繼承,父類中不提供任何實現
* @param rs
* 查詢返回的結果集
* @param data
* 查詢後保存的對象
* @return
* 參數data
* @throws SQLException
* 必須處理異常
*/
protected abstract void toObject(ResultSet rs, T entity) throws SQLException;
/**
* 查詢結果數量
* @param sql
* @return
*/
public int queryCount(String sql){
int count = 0;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
Connection conn = ConnectionUtils.getConnection();
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
if(rs.next()){
count = rs.getInt(1);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
ConnectionUtils.closeAll(rs, pstmt, Boolean.TRUE);
}
return count;
}
/**
* 調用子類方法的入口,子類中只需要提供toObjectOfList方法的實現
* 查詢不帶參數實現
* @param sql
* @param values
* @return
*/
public List<T> queryList(String sql){
List<T> data = new ArrayList<>();
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
Connection conn = ConnectionUtils.getConnection();
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
toObjectOfList(rs, data);
} catch (SQLException e) {
e.printStackTrace();
}finally {
ConnectionUtils.closeAll(rs, pstmt, Boolean.TRUE);
}
return data;
}
/**
* 分頁查詢,注意調用者必須驗證返回值中的success函數
* @param sql
* 查詢的SQL語句,不需要limit
* @param curPage
* 當前頁碼
* @param pageSize
* 每頁顯示條數
* @return
* 保存分頁相關參數的map集合
* totalRows:數據條數
* page:頁數
* data:返回數據
* success:驗證分頁 true->成功 false->失敗
*/
public Map<String, Object> queryListByPage(String sql, int curPage, int pageSize){
Map<String, Object> map = new HashMap<>();
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
Connection conn = ConnectionUtils.getConnection();
String countSql = sql.replace("*", "count(*)");
pstmt = conn.prepareStatement(countSql);
rs = pstmt.executeQuery();
int count = rs.next() ? rs.getInt(1) : 0;
int pageCount = count%pageSize == 0 ? count/pageSize : count/pageSize+1;
map.put("totalRows", count);
map.put("page", pageCount);
List<T> data = new ArrayList<>();
int begin = (curPage-1)*pageSize+1;
sql = sql.contains("where") ? sql + " limit " : sql + " where 1=1 limit ";
sql = sql + begin + "," + pageSize;
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
toObjectOfList(rs, data);
map.put("data", data);
map.put("success", true);
} catch (SQLException e) {
map.put("success", false);
e.printStackTrace();
}finally {
ConnectionUtils.closeAll(rs, pstmt, Boolean.TRUE);
}
return map;
}
/**
* 可以由子類繼承,父類中所提供默認實現的內部是由子類實現的toObject方法
* @param rs
* 查詢返回的結果集
* @param data
* 查詢後保存的集合
* @return
* 參數data
* @throws SQLException
* 必須處理異常
*/
protected List<T> toObjectOfList(ResultSet rs, List<T> data) throws SQLException{
if(rs != null && data != null){
int rowCount = rs.last() ? rs.getRow() : 0;
rs.beforeFirst();
try {
T t;
for(int i=0; i< rowCount; i++){
t = this.entityClass.newInstance();
toObject(rs, t);
data.add(t);
}
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
return data;
}
/**
* 添加一條數據方法,參數放到SQL中直接執行
* @param sql 執行SQL
* @return 驗證操作成功
*/
public boolean insert(String sql){
PreparedStatement pstmt = null;
Connection conn = null;
try {
conn = ConnectionUtils.getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.executeUpdate();
conn.commit();
return true;
} catch (SQLException e) {
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
return false;
}finally{
ConnectionUtils.closeAll(null, pstmt, Boolean.TRUE);
}
}
/**
* 添加一條數據方法,參數的傳遞使用實體的值和實體對應dao層封裝的賦值方法
* @param sql 執行SQL
* @param t 帶參數的實體對象
* @return 驗證操作成功
*/
public boolean insert(String sql, T entity){
PreparedStatement pstmt = null;
Connection conn = null;
try {
conn = ConnectionUtils.getConnection();
pstmt = conn.prepareStatement(sql);
doInsertSetPstmt(pstmt, entity);
pstmt.executeUpdate();
conn.commit();
return true;
} catch (SQLException e) {
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
return false;
}finally{
ConnectionUtils.closeAll(null, pstmt, Boolean.TRUE);
}
}
/**
* 批量添加數據,參數的傳遞使用實體的值和實體對應dao層封裝的賦值方法
* @param sql 執行SQL
* @param dataList 保存帶參數實體對象的集合
* @return 驗證操作成功
*/
public boolean batchInsert(String sql, List<T> dataList){
PreparedStatement pstmt = null;
Connection conn = null;
try {
conn = ConnectionUtils.getConnection();
pstmt = conn.prepareStatement(sql);
conn.setAutoCommit(false);
int count = 0;
for (T t : dataList) {
doInsertSetPstmt(pstmt, t);
pstmt.addBatch();
if(++count == 500){
pstmt.executeBatch();
count = 0;
}
}
pstmt.executeBatch();
conn.commit();
return true;
} catch (SQLException e) {
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
return false;
}finally{
ConnectionUtils.closeAll(null, pstmt, Boolean.TRUE);
}
}
/**
* 由子類繼承,父類中不提供任何實現
* @param pstmt
* @param entity
* @throws SQLException
*/
protected abstract void doInsertSetPstmt(PreparedStatement pstmt, T entity) throws SQLException;
/**
* 刪除SQL中的數據
* @param sql
* @return
*/
public boolean delete(String sql){
PreparedStatement pstmt = null;
Connection conn = null;
try {
conn = ConnectionUtils.getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.executeUpdate();
doDelete(conn);
return true;
} catch (SQLException e) {
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
return false;
}finally{
ConnectionUtils.closeAll(null, pstmt, Boolean.TRUE);
}
}
/**
* 根據id集合批量刪除
* @param sql
* @param ids
* @return
*/
public boolean batchDelete(String sql, List<Integer> ids){
PreparedStatement pstmt = null;
Connection conn = null;
try {
conn = ConnectionUtils.getConnection();
pstmt = conn.prepareStatement(sql);
conn.setAutoCommit(false);
int count = 0;
for (int i : ids) {
pstmt.setInt(1, i);
pstmt.addBatch();
if(++count == 500){
pstmt.executeBatch();
count = 0;
}
}
pstmt.executeBatch();
doDelete(conn);
return true;
} catch (SQLException e) {
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
return false;
}finally{
ConnectionUtils.closeAll(null, pstmt, Boolean.TRUE);
}
}
protected abstract void doDelete(Connection conn) throws SQLException;
/**
* 修改SQL中的數據
* @param sql
* @return
*/
public boolean update(String sql){
PreparedStatement pstmt = null;
Connection conn = null;
try {
conn = ConnectionUtils.getConnection();
pstmt = conn.prepareStatement(sql);
pstmt.executeUpdate();
conn.commit();
return true;
} catch (SQLException e) {
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
return false;
}finally{
ConnectionUtils.closeAll(null, pstmt, Boolean.TRUE);
}
}
/**
* 批量修改集合中的所有數據
* @param sql
* @param dataList
* @return
*/
public boolean batchUpdate(String sql, List<T> dataList){
PreparedStatement pstmt = null;
Connection conn = null;
try {
conn = ConnectionUtils.getConnection();
pstmt = conn.prepareStatement(sql);
conn.setAutoCommit(false);
int count = 0;
for (T t : dataList) {
doUpdateSetPstmt(pstmt, t);
pstmt.addBatch();
if(++count == 500){
pstmt.executeBatch();
count = 0;
}
}
pstmt.executeBatch();
conn.commit();
return true;
} catch (SQLException e) {
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
return false;
}finally{
ConnectionUtils.closeAll(null, pstmt, Boolean.TRUE);
}
}
protected abstract void doUpdateSetPstmt(PreparedStatement pstmt, T entity) throws SQLException;
public java.sql.Date toSqlDate(Date date){
java.sql.Date sqlDate = new java.sql.Date(new Date().getTime());
if(date != null)
sqlDate = new java.sql.Date(date.getTime());
return sqlDate;
}
public Date toUtilDate(java.sql.Date sqlDate){
Date date = new Date();
if(sqlDate != null)
date = new Date(sqlDate.getTime());
return date;
}
}
連接MySQL數據庫的工具類:
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 ConnectionUtils {
// 線程單例
private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
private static String url;
private static String username;
private static String password;
static {
// 裝載驅動參數
try {
ClassLoader classLoader = ConnectionUtils.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("standard.properties");
Properties props = new Properties();
props.load(is);
url = props.getProperty("url");
username = props.getProperty("username");
password = props.getProperty("password");
// 註冊驅動
Class.forName(props.getProperty("jdbc.driverName"));
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException{
Connection con = tl.get();
if (con == null || con.isClosed()) {
con = DriverManager.getConnection(url, username, password);
tl.set(con);
}
return con;
}
public static void closeConnection() {
Connection conn = tl.get();
if (conn == null)
return;
try {
if (!conn.isClosed()) {
//關閉數據庫連接
conn.close();
}
} catch (SQLException e) {
System.err.println("#ERROR# :關閉數據庫連接發生異常,請檢查!\n" + e.getMessage());
}
}
public static void closeAll(ResultSet rs, Statement stmt, boolean closeConn) {
try {
if (rs != null)
rs.close();
if (stmt != null)
stmt.close();
if(closeConn)
closeConnection();
} catch (Exception e) {
e.printStackTrace();
}
}
}
實體類如下:
public class Area{
//----------- object properties
private Integer id;
private String name;
private Integer parent_id;
private Byte sort;
private Byte deep;
private String city_code;
private String region;
private Integer status;
private Integer ad_code;
//------------ database columns
public static final String ID = "AREA_ID";
public static final String NAME = "AREA_NAME";
public static final String PARENT_ID = "AREA_PARENT_ID";
public static final String SORT = "AREA_SORT";
public static final String DEEP = "AREA_DEEP";
public static final String CITY_CODE = "CITY_CODE";
public static final String REGION = "AREA_REGION";
public static final String STATUS = "AREA_STATUS";
public static final String AD_CODE = "AD_CODE";
//------------ get or set ...
dao實現類如下:
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.entity.Area;
public class AreaDao extends BaseDao<Area>{
@Override
protected void toObject(ResultSet rs, Area data) throws SQLException{
if(rs.next()){
data.setId(rs.getInt(Area.ID));
data.setName(rs.getString(Area.NAME));
data.setParent_id(rs.getInt(Area.PARENT_ID));
data.setSort(rs.getByte(Area.SORT));
data.setDeep(rs.getByte(Area.DEEP));
data.setCity_code(rs.getString(Area.CITY_CODE));
data.setRegion(rs.getString(Area.REGION));
data.setStatus(rs.getInt(Area.STATUS));
data.setAd_code(rs.getInt(Area.AD_CODE));
}
}
@Override
protected void doInsertSetPstmt(PreparedStatement pstmt, Area t) throws SQLException {
throw new SQLException("This table is not allowed to be added");
}
@Override
protected void doUpdateSetPstmt(PreparedStatement pstmt, Area t) throws SQLException {
throw new SQLException("This form is not allowed to be amended");
}
@Override
protected void doDelete(Connection conn) throws SQLException {
throw new SQLException("This form is not allowed to be deleted");
}
}
我這裏只是封裝了一些冗餘代碼,並沒有完成屬性映射,一開始想着是用反射實現,後來發現時間不夠。。。 然後就先寫到這裏了,寫的過程想到我們可以用自定義註解來配置實體和表的映射,後面有時間會研究研究。
然後突然發現ORM框架其實不難(說這句話的時候我還沒有研究過人家框架的源碼,也許並不像我想的那麼簡單),也許以後有時間會自己完成一個ORM框架吧,先到這裏,去趕項目了。
最後,這只是給像我這樣菜鳥看的,大神勿噴[拜謝]