文章目录
simple-ibatis 手写了一个ORM框架
前文介绍
在学习mybatis源码之余,自己完成了一个简单的ORM框架,已完成基本SQL的执行和对象关系映射。本周在此基础上,又加入了缓存和事务功能。
源码地址
前叙博文地址
缓存 com.simple.ibatis.cache
缓存接口-Cache
public interface Cache {
/**放入缓存*/
void putCache(String key,Object val);
/**获取缓存*/
Object getCache(String key);
/**清空缓存*/
void cleanCache();
/**获取缓存健数量*/
int getSize();
/**移除key的缓存*/
void removeCache(String key);
}
提供基本的缓存功能
缓存基本实现类-SimpleCache
public class SimpleCache implements Cache{
private static Map<String,Object> map = new HashMap<>();
@Override
public void putCache(String key, Object val) {
map.put(key,val);
}
@Override
public Object getCache(String key) {
return map.get(key);
}
@Override
public void cleanCache() {
map.clear();
}
@Override
public int getSize() {
return map.size();
}
@Override
public void removeCache(String key) {
map.remove(key);
}
}
内部使用HashMap来实现一个简单的缓存器,基本是对HashMap的封装。
具备LRU淘汰策略-LruCache
/**
* @author xiabing
* @description: 缓存包装类
*/
public class LruCache implements Cache{
private static Integer cacheSize = 100;
private static Float loadFactory = 0.75F;
private Cache trueCache;
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
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.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源码。mybatis缓存实现
项目代码展示
可参考github项目中Test类中shouldGetCache()方法
@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类。
事务功能com.simple.ibatis.transaction
事务接口-Transaction
/**
* @Author xiabing
* @Desc 增加事务功能
**/
public interface Transaction {
/**获取链接*/
Connection getConnection() throws SQLException;
/**提交*/
void commit() throws SQLException;
/**回滚*/
void rollback() throws SQLException;
/**关闭*/
void close() throws SQLException;
}
JDBC事务-SimpleTransaction
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)
项目代码展示
@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();
}
上述代码在github项目中Test类中shouldOpenTransaction()方法上,可自行debug测试。
结束语
此次在已有的基础上增加了缓存和事务的功能。又是一次学习之旅。因为代码全手写,没有COPY任何一句代码,不是很完善,请见谅。如果觉的感兴趣,请给我个star支持下。因为自己想一直去维护这个项目,如果你也感兴趣,可以私聊我和我一起做下去,一起写好这个开源项目。