1、实现要求java
一、数据访问层的职责是对数据库进行增删改查的操做,因此能够很是单一,仅仅只须要一个inteface便可搞定;git
二、全自动ORM不利于SQL的优化与SQL的定制,因此TeaFrameWork ORM准备用半自动的方式实现,开发人员须要写SQL;sql
三、告别配置文件,纯注解;数据库
四、接口每一个方法只须要一个参数,能够是PO对象、能够是MAP、能够是8大基本数据类型+String和Date安全
五、动态绑定SQL框架
六、支持Oracle、Mysqlide
七、自动分页工具
八、占位符用#号,如:#id#,#name#,这个和ibatis一致优化
2、分析.net
一、设计上ORM只须要inteface,那么具体实现类必须由框架生成,对比了不少字节码生成工具以后,决定采用cglib
二、对数据库的操做,本质上只有两种:读、写。
(1)、读即Select语句,返回值类型:8大基本数据类型+String和Date、PO对象、List<PO对象>、List<Map<String,Object>>,这里咱们限定了返回的类型,基本上知足了平常开发
(2)、写:insert、update、delete等,insert操做中有个主键获取问题,能够自动生成,也能够写SQL得到,例如Oracle的select s_users.nextval from dual
3、具体实现
一、注解
(1)、@TeaDao标示这个inteface是数据访问层,让bean容器启动时能够扫描到
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface TeaDao { public String value() default ""; }
(2)、@SQL给具体方法绑定SQL语句,如:@SQL("select * from users") public List<User> getAllUser();
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface SQL { public String value(); }
(3)、@GetPrimaryKey注解生成主键的语句,一般和insert语句配合使用
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface GetPrimaryKey { public String sql(); public String primaryKeyProperty(); }
如:
@GetPrimaryKey(sql = "select s_users.nextval from dual", primaryKeyProperty = "id") @SQL("insert into users(id,name,password,createdate) values(#id#,#name#,#password#,#createdate#)") public int add(Map<String, Object> map);
(4)、@AutoIncrement注解新增时由数据库自动生成主键,和新增配合使用
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface AutoIncrement { }
(5)、@DynamicSQL注解方法的SQL是动态传入,在查询场景下使用
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface DynamicSQL { }
二、代理类OrmProxy,具体拦截inteface的方式,执行SQL
public class OrmProxy implements InterfaceExecutor { private final static String SELECT = "select"; private final static String INSERT = "insert"; private static OrmProxy instance; private OrmProxy() { } public synchronized static OrmProxy getInstance() { if (instance == null) { instance = new OrmProxy(); } return instance; } @Override public Object invoke(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { if (method.getDeclaringClass().equals(java.lang.Object.class)) { return proxy.invokeSuper(obj, args); } if (!method.isAnnotationPresent(SQL.class) && !method.isAnnotationPresent(DynamicSQL.class)) { throw new TeaOrmException("没有绑定SQL"); } if (args != null && args.length > 1) { throw new TeaOrmException("只能传递一个参数"); } if (method.isAnnotationPresent(GetPrimaryKey.class) && method.isAnnotationPresent(AutoIncrement.class)) { throw new TeaOrmException("GetPrimaryKey和AutoIncrement不能同时注解在一个方法上"); } if (method.getAnnotation(SQL.class) != null && method.getAnnotation(DynamicSQL.class) != null) { throw new TeaOrmException("SQL和DynamicSQL不能同时注解在一个方法上"); } if (TranscationThreadVariable.get() == null || !TranscationThreadVariable.get()) { if (ConnectionThreadVariable.getConnetion() == null) { ConnectionThreadVariable.setConnetion(DataSourceHelp.getConnection()); } } try { if (method.isAnnotationPresent(SQL.class)) { String sql = method.getAnnotation(SQL.class).value().trim(); AbstractDataBind dataBind = DataBindFactory .getDataBind(args == null || args.length == 0 ? null : args[0]); if (!SELECT.equalsIgnoreCase(sql.substring(0, 6))) { boolean isAutoIncrement = false; if (INSERT.equalsIgnoreCase(sql.substring(0, 6))) { if (method.getAnnotation(AutoIncrement.class) != null) { isAutoIncrement = true; } if (method.getAnnotation(GetPrimaryKey.class) != null) { Object object = dataBind.fillPrimaryKey(method, args[0]);// 填充主键 dataBind.excuteUpdate(sql, args == null || args.length == 0 ? null : args[0], isAutoIncrement); return object; } } return dataBind.excuteUpdate(sql, args == null || args.length == 0 ? null : args[0], isAutoIncrement); } else { return QueryResultProcesser.createQueryResult( dataBind.excuteQuery(sql, args == null || args.length == 0 ? null : args[0]), method); } } else if (method.isAnnotationPresent(DynamicSQL.class)) { String sql = DynamicSqlUtil.get() == null ? null : DynamicSqlUtil.get().trim(); if (null == sql || "".equals(sql)) { throw new TeaOrmException("SQL语句不能为空"); } if (sql.length() < 6 || !SELECT.equalsIgnoreCase(sql.substring(0, 6))) { throw new TeaOrmException("只能绑定select语句"); } return QueryResultProcesser.createQueryResult(DataBindFactory.getDataBind(null).excuteQuery(sql, args == null || args.length == 0 ? null : args[0]), method); } } catch (Exception e) { throw new TeaOrmException(e); } finally { if (TranscationThreadVariable.get() == null || !TranscationThreadVariable.get()) { ConnectionThreadVariable.getConnetion().close(); ConnectionThreadVariable.clearThreadVariable(); } } return null; } }
代码解释:
(1)、用于都是method执行,没有共享变量,因此没有线程安全问题,故而这里用单例模式
(2)、获取SQL分两大块,动态SQL和固定注解SQL,动态SQL只用于查询场景。对于新增,须要获取主键生成方案(sql生成和自动生成)
(3)、InterfaceExecutor接口会在Bean容器设计中详细讲到
(4)、Transcation相关的代码,会在事务设计中详细讲到
自此,一个ORM核心的代码已经完成,剩下SQL的执行过程、占位符替换,请关注《TeaFramework——ORM框架的实现(二)》
项目地址:https://git.oschina.net/lxkm/teaframework
博客:https://my.oschina.net/u/1778239/blog