轻量级DAO层实践初体验
? ? 最近快被 Hibernate 給坑哭了,有了自己動手實現(xiàn) ORM 映射 DAO 的沖動。
? ? ? 工作之余折騰了快一星期,總算是有點小成就。
? ? ? 現(xiàn)打算將過程記錄下來,方便自己后續(xù)回顧填補遺漏。
回到頂部?1. 傳統(tǒng) JDBC 實現(xiàn)過程
?
- 無論你項目中使用的是什么樣的 ORM 框架[Hibernate/MyBatis.....],或者是現(xiàn)在大熱的領(lǐng)域模型 DSL DAO層,都是在傳統(tǒng) JDBC的基礎(chǔ)上進行的封裝。
- 騷年如果你上手就是 DAO 層框架,沒有見過上述的幾個家伙的話,建議你反編譯 JDK去和他們打個招呼。
- 傳統(tǒng) JDBC 實現(xiàn)獲取數(shù)據(jù)庫數(shù)據(jù)的代碼(隨上圖序列圖)
- PreparedStatement/Statement 提供的兩種不同的運行 執(zhí)行Sql 事物對象。
- PreparedStatement 為預(yù)編譯 Sql,執(zhí)行前已經(jīng)被編譯,DBMS 只需執(zhí)行即可,這就意味這 這種形式的 Sql 語句執(zhí)行效率相當(dāng)高。
- Statement ?為執(zhí)行時才會進行編譯Sql,然后被?DBMS 執(zhí)行,所以這個對象在執(zhí)行 Sql 不是很頻繁時,相對不錯。
- PreparedStatement 效率高,還可以有效的防止 Sql 注入,但會占用多余的內(nèi)存空間(用于預(yù)編譯)。
- 就好像是胸大,臀漂亮的妹子,臉不好看,你需要犧牲一部分東西,去換取另外一部分東西,沒有絕對完美的選擇。
?2. 基于注解的 ORM 實踐
? ? ? JDBC 訪問數(shù)據(jù)庫的方式是最高效的,沒有之一,好比是高級編程語言的效率永遠(yuǎn)不可能高于底層匯編語言是一樣的道理。
? ? ? 但是 JDBC 對于程序員來說太難駕馭了,沒辦法將關(guān)系數(shù)據(jù)庫中的數(shù)據(jù)抽象到 Java的面向?qū)ο蟮氖澜纭?/span>
? ? ? 下面是我業(yè)余時間在摸索出來的不依靠任何框架,只使用 JDK自帶的注解和反射的 DAO 層實現(xiàn),
? ? ? 其中還有很多的問題,但是大體的樣子已經(jīng)很可愛了。
? ? ? a.定義你自己的 DAO 表名注解
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) @Inherited public @interface TableName {String value(); }? ? ?b.在 POJO (與數(shù)據(jù)庫表結(jié)構(gòu)對應(yīng)) 中是添加?TableName?注解
@TableName("tmp_services") public class Service extends BaseVO<Service>{private String id;private String name;private String theme;private String type;private String descrition;private String XSD;private String remark;.......... }??? d.獲取注解表名、組織 Sql 、調(diào)整姿勢
public <T> List<T> find(Class<T> clazz, Map param, Connection connection) throws DataOptException {TableName tableName = clazz.getAnnotation(TableName.class);if (tableName == null) {throw new DataOptException("A1-308", "沒有找到類[" + clazz.getName() + "]所映射的表!");} else {String sql = "SELECT * FROM " + tableName.value() + " WHERE 1=1 ";ArrayList paras = new ArrayList();if (param != null) {Iterator<Map.Entry<String, Object>> iterator = param.entrySet().iterator();while (iterator.hasNext()) {Map.Entry<String, Object> entry = iterator.next();sql = sql + " AND " + entry.getKey() + " = ?";paras.add(entry.getValue());}}return this.select(connection, sql, paras, clazz);}}??? e.熟悉的JDBC 操作、獲取查詢結(jié)果集、反射填充POJO屬性
public <T> List<T> select(Connection connection, String sql, List<Object> paras, Class<T> clazz) throws DataOptException {ArrayList retList = new ArrayList();try {PreparedStatement preparedStatement = connection.prepareStatement(sql);Object bean;Iterator iterator;if (paras != null) {int count = 1;iterator = paras.iterator();while (iterator.hasNext()) {bean = iterator.next();preparedStatement.setObject(count++, bean);}}ResultSet resultSet = preparedStatement.executeQuery();String fname;Object value;List fields = getCanWriteField(clazz);Iterator filedIter = fields.iterator();Field field;while (filedIter.hasNext()) {field = (Field) filedIter.next();field.setAccessible(true); //抑制java 對修飾符的檢查 }HashSet hashSet = new HashSet();ResultSetMetaData metaData = resultSet.getMetaData();int i;for (i = 1; i <= metaData.getColumnCount(); ++i) {hashSet.add(metaData.getColumnLabel(i).toLowerCase());}for (i = fields.size() - 1; i >= 0; --i) {if (!hashSet.contains(((Field) fields.get(i)).getName().toLowerCase())) {fields.remove(i);}}for (; resultSet.next(); retList.add(bean)) {bean = clazz.newInstance();filedIter = fields.iterator();while (filedIter.hasNext()) {field = (Field) filedIter.next();fname = field.getName();if (ClassUtils.isAssignable(field.getType(), Date.class)) {Timestamp timestamp = resultSet.getTimestamp(fname);if (timestamp != null) {field.set(bean, timestamp);}continue;}value = resultSet.getObject(fname);if (value != null) {try {field.set(bean, reflect(field.getType(), value));} catch (Exception e) {e.printStackTrace();}}}}} catch (Throwable e) {throw new DataOptException("A1-001", e.getMessage(), e);} finally {this.closeConnection(connection);}return retList;}? ? f. ?將?ResultSet 獲取的值?轉(zhuǎn)換 POJO 屬性時,判斷邏輯稍微多一點,基本囊括了主流的 java 基本類型...
?View Code? ?d.項目中的使用方式
Map<String,Object> map = new HashMap<>();map.put("uuid","c9ea709cb30d4954a33dfec01d3ef142");List<Service> serviceList = selecter.find(EjbService.class, map, connection);? ? ? ?PO、Map 作為參數(shù),使用方式是不是很簡單呢?
? ? ? ?只是對查詢進行了的封裝,后續(xù)需要關(guān)注下更新和插入、與Spring 的 整合、數(shù)據(jù)連接池的整合....
本文轉(zhuǎn)自O(shè)rson博客園博客,原文鏈接:http://www.cnblogs.com/java-class/p/5512407.html,如需轉(zhuǎn)載請自行聯(lián)系原作者
總結(jié)
以上是生活随笔為你收集整理的轻量级DAO层实践初体验的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: zabiix监控磁盘io
- 下一篇: Nginx源代码安装