在學習mybatis源碼之餘,本身完成了一個簡單的ORM框架。已完成基本SQL的執行和對象關係映射。本週在此基礎上,又加入了緩存和事務功能。全部代碼都沒有copy,若是也對此感興趣,請賞個Star。html
項目地址:simple-ibatisjava
第一版博文地址:博客園博文mysql
public interface Cache { /**放入緩存*/ void putCache(String key,Object val); /**獲取緩存*/ Object getCache(String key); /**清空緩存*/ void cleanCache(); /**獲取緩存健數量*/ int getSize(); /**移除key的緩存*/ void removeCache(String key); }
自定義框架緩存接口,提供基本的增刪改查功能。git
public class SimpleCache implements Cache{ // 內部使用HashMap做爲緩存實現 private static Map<String,Object> map = new HashMap<>(); // 調用map.put()方法實現存緩存功能 @Override public void putCache(String key, Object val) { map.put(key,val); } // 調用map.get()方法實現取緩存功能 @Override public Object getCache(String key) { return map.get(key); } // 調用map.clear()方法實現清空緩存功能 @Override public void cleanCache() { map.clear(); } // 調用map.size()方法獲取緩存數量 @Override public int getSize() { return map.size(); } // 調用map.remove()方法移除緩存 @Override public void removeCache(String key) { map.remove(key); } }
simple-ibatis完成對HasaMap的封裝,實現了基本的緩存獲取,刪除,清除等功能。github
/** * @author xiabing * @description: 緩存包裝類,具有Lru淘汰策略功能 */ public class LruCache implements Cache{ // 默認緩存數 private static Integer cacheSize = 100; // 負載因子 private static Float loadFactory = 0.75F; // 真實緩存 private Cache trueCache; // 重寫LinkedHashMap方法實現Lru功能 private Map<String,Object> linkedCache; // 待移除的緩存元素 private static Map.Entry removeEntry; public LruCache(Cache trueCache){ this(cacheSize,loadFactory,trueCache); } public LruCache(Integer cacheSize, Float loadFactory, Cache trueCache) { this.cacheSize = cacheSize; this.loadFactory = loadFactory; this.trueCache = trueCache; this.linkedCache = new LinkedHashMap<String, Object>(cacheSize,loadFactory,true){ @Override // 當緩存數大於設置的默認緩存數時,linkedHashMap會淘汰最近最少使用的元素,獲取此元素,在真實緩存中淘汰便可 protected boolean removeEldestEntry(Map.Entry eldest) { if(getSize() > cacheSize){ removeEntry = eldest; return true; } return false; } }; } @Override public void putCache(String key, Object val) { this.trueCache.putCache(key,val); this.linkedCache.put(key,val); if(removeEntry != null){ // 若找到了最近最少元素,則進行移除 removeCache((String)removeEntry.getKey()); removeEntry = null; } } @Override public Object getCache(String key) { // linkedCache獲取的意義是觸發linkedHashMap元素排序 linkedCache.get(key); return trueCache.getCache(key); } @Override public void cleanCache() { trueCache.cleanCache(); linkedCache.clear(); } @Override public int getSize() { return trueCache.getSize(); } @Override public void removeCache(String key) { trueCache.removeCache(key); } }
LruCache是根據LinkedHashMap的特性來實現,若對此有疑問,可參考mybatis關於LruCache功能的實現 - mybatis緩存介紹sql
@Test // 測試緩存獲取 public void shouldGetCache() throws SQLException { // 初始化鏈接池 PoolDataSource poolDataSource = new PoolDataSource("com.mysql.jdbc.Driver","jdbc:mysql://101.132.150.75:3306/our-auth","root","root"); Config config = new Config("com/simple/ibatis/mapper",poolDataSource); // 設置全局配置,開啓緩存 config.setOpenCache(true); // 獲取執行器 Executor simpleExecutor = config.getExecutor(); UserMapper userMapper = simpleExecutor.getMapper(UserMapper.class); User user = new User(); user.setId(1); user.setName("root"); // 第一次調用 List<User> userList = userMapper.getUsers(user); // 第二次調用,我在源碼中有打印輸出,若使用了緩存,則打印語句 List<User> userList1 = userMapper.getUsers(user); simpleExecutor.close(); }
結果打印以下 this is cache .感興趣的能夠本身試下數據庫
cache我設置了全局可配置,默認生成的是LruCache。並在更新,修改,刪除的SQL操做前強制刷新緩存。詳細代碼邏輯見項目中SimpleExecutor類。緩存
/** * @Author xiabing * @Desc 增長事務功能 **/ public interface Transaction { /**獲取連接*/ Connection getConnection() throws SQLException; /**提交*/ void commit() throws SQLException; /**回滾*/ void rollback() throws SQLException; /**關閉*/ void close() throws SQLException; }
package com.simple.ibatis.transaction; import com.simple.ibatis.datasource.PoolDataSource; import java.sql.Connection; import java.sql.SQLException; /** * @Author xiabing * @Desc 事務的簡單實現 **/ public class SimpleTransaction implements Transaction{ private Connection connection; // 數據庫鏈接 private PoolDataSource dataSource; // 數據源 private Integer level = Connection.TRANSACTION_REPEATABLE_READ;; // 事務隔離級別 private Boolean autoCommmit = true; // 是否自動提交 public SimpleTransaction(PoolDataSource dataSource){ this(dataSource,null,null); } public SimpleTransaction(PoolDataSource dataSource, Integer level, Boolean autoCommmit) { this.dataSource = dataSource; if(level != null){ this.level = level; } if(autoCommmit != null){ this.autoCommmit = autoCommmit; } } @Override public Connection getConnection() throws SQLException{ this.connection = dataSource.getConnection(); this.connection.setAutoCommit(autoCommmit); this.connection.setTransactionIsolation(level); return this.connection; } @Override public void commit() throws SQLException{ if(this.connection != null){ this.connection.commit(); } } @Override public void rollback() throws SQLException{ if(this.connection != null){ this.connection.rollback(); } } /**關閉連接前,若設置了自動提交爲false,則必須進行回滾操做*/ @Override public void close() throws SQLException{ if(!autoCommmit && connection != null){ connection.rollback(); } /**放回鏈接池*/ if(connection != null){ dataSource.removeConnection(connection); } /**連接設爲null*/ this.connection = null; } }
simpleTransaction主要將事務管理功能交給了數據庫自己(即connection),事務隔離級別默然是mysql的事務隔離級別。經過對Connection的管理,進而實現對connection一系列操做的事務控制。mybatis
Test public void shouldOpenTransaction() { /**基本配置*/ PoolDataSource poolDataSource = new PoolDataSource("com.mysql.jdbc.Driver","jdbc:mysql://101.132.150.75:3306/our-auth","root","root"); Config config = new Config("com/simple/ibatis/mapper",poolDataSource); /**設置爲啓用事務,關閉自動提交*/ config.setOpenTransaction(true); /**獲取執行器*/ Executor simpleExecutor = config.getExecutor(); UserMapper userMapper = simpleExecutor.getMapper(UserMapper.class); User user = new User(); user.setId(1); user.setName("xiabing"); /**更新名字爲xiabing,但未提交*/ userMapper.update(user); User user1 = userMapper.getUserById(1); /**獲取ID爲1的名字,爲root,說明上文的語句尚未提交*/ System.out.println(user1.getName()); /**事務提交語句*/ //simpleExecutor.commit(); }
若不提交事物,即執行 simpleExecutor.commit()語句,更新語句將不會自動提交到數據庫。上述代碼在github項目中Test類中shouldOpenTransaction()方法上,可自行debug測試。app
總結:
該項目屬於我抱着學習的心態去作的項目,將Mybatis源碼一步步拆解,在實踐中去領悟其強大的地方。這次在已有的基礎上增長了緩存和事務的功能。又是一次學習之旅。由於代碼全手寫,沒有COPY任何一句代碼,不是很完善,請見諒。若是覺的感興趣,請給我個star支持下。由於本身想一直去維護這個項目,若是你也感興趣,能夠私聊我和我一塊兒作下去,一塊兒寫好這個開源項目。最後,真心求Star了 --------
項目地址:simple-ibatis