Github源碼下載地址:https://github.com/chenxingxing6/myorm
CSDN源碼下載地址:https://download.csdn.net/download/m0_37499059/11783237
一、前言
ORM對象關係映射(Object Relational Mapping),用於實現面向對象編程語言裏不通類型系統的數據之間進行轉換。簡單來說,ORM就是通過使用描述對象和數據庫之間映射的元數據,將程序中的對象與關係數據庫進行相互映射。
二、先簡單瞭解一下Mybatis
MyBatis 是一款優秀的持久層框架,它支持定製化 SQL、存儲過程以及高級映射。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設置參數以及獲取結果集。MyBatis 可以使用簡單的 XML 或註解來配置和映射原生信息,將接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java對象)映射成數據庫中的記錄。
1.SqlSessionFactory是線程安全的
2.qlSession是單線程對象,因爲它是非線程安全的
流程描述:
1.加載Mybatis全局配置文件並解析,生成Configuration對象和MapperdStatement
2.SqlSessionFactoryBuilder通過Configuration對象構建SqlSessionFactory
3.通過SqlSessionFactory獲取sqlSession
4.sqlSession和數據庫進行交互
三、MyORM實現
主要完成的功能【基本CURD是可以支持的】
1.通過自己實現的ORM,進行增刪改查demo
2.@Param註解解析,支持註解到對象和基本數據類型
3.用dtd文件定義Mapper.xml文檔的合法構建模塊
4.根據resultType,對結果進行處理
5.除了xml配置方式外,新加註解方式@Select @Insert @Delete @Update
我的實現思路
1.解析配置文件,初始化數據庫連接,創建sqlSession池,交給SqlSessionFactory管理
2.創建Execute,底層調用JDBC操作數據庫
3.創建MapperProxy代理對象,動態代理Mapper接口
4.大體架子搭建好後,可以繼續完善,比如@Param註解.
5.測試就直接使用單測測試就可以了
四、MyORM項目結構
CREATE TABLE `sys_role` (
`role_id` bigint(20) NOT NULL AUTO_INCREMENT,
`role_name` varchar(100) DEFAULT NULL COMMENT '角色名稱',
`remark` varchar(100) DEFAULT NULL COMMENT '備註',
`dept_id` bigint(20) DEFAULT NULL COMMENT '部門ID',
`create_time` datetime DEFAULT NULL COMMENT '創建時間',
PRIMARY KEY (`role_id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='角色'
INSERT INTO cloud_disk.sys_role (role_id, role_name, remark, dept_id, create_time) VALUES (1, '超級管理員', '最高權限', 34, '2018-07-31 19:27:42');
INSERT INTO cloud_disk.sys_role (role_id, role_name, remark, dept_id, create_time) VALUES (2, '管理員', '權限比較少', 9, '2018-07-31 19:28:58');
INSERT INTO cloud_disk.sys_role (role_id, role_name, remark, dept_id, create_time) VALUES (3, 'IT經理', 'IT用
4.1 增刪改查Demo
package com.demo;
import com.alibaba.fastjson.JSON;
import com.test.entry.Role;
import com.test.mapper.RoleMapper;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author: cxx
* @Date: 2019/9/18 12:42
*/
public class MapperTest {
private RoleMapper roleMapper;
@Before
public void init(){
// 使用弱引用創建SqlSessionFactoryBuilder,保證下次GC時回收該對象。
WeakReference<SqlSessionFactoryBuilder> builder = new WeakReference<>(new SqlSessionFactoryBuilder());
String mapxmlPath = "mapper";
SqlSessionFactory factory = builder.get().build(mapxmlPath);
roleMapper = factory.getMapper(RoleMapper.class);
}
/**
* 查詢(普通 & 有@param註解)
*/
@Test
public void test01(){
Role role1 = roleMapper.getRoleById(1L);
System.out.println("普通方式:"+JSON.toJSONString(role1));
Role role2 = roleMapper.getRoleByIdAndDeptId(1L, 34L);
System.out.println("@Param註解:"+JSON.toJSONString(role2));
}
/**
* 刪除
*/
@Test
public void test02(){
int result = roleMapper.deleteById(36L);
System.out.println(result >= 1 ? "刪除成功" : "刪除失敗");
}
/**
* 插入
*/
@Test
public void test03(){
Role role = new Role();
role.setRoleId(Long.valueOf(new Random().nextInt(100)));
role.setDeptId(1L);
role.setRemark("remark");
role.setRoleName("roleName");
role.setCreateTime(new Date());
int result = roleMapper.insert(role);
System.out.println(result >= 1 ? "插入成功" : "插入失敗");
}
/**
* 修改
*/
@Test
public void test04(){
int result = roleMapper.updateRoleName(10L, "update remark");
System.out.println(result >= 1 ? "修改成功" : "修改失敗");
}
}
4.2 RoleMapper.java
package com.test.mapper;
import com.test.entry.Role;
import org.apache.ibatis.annotations.Param;
/**
* @Author: cxx
* @Date: 2019/9/18 0:48
*/
public interface RoleMapper {
public Role getRoleById(Long id);
public Role getRoleByIdAndDeptId(Long id, @Param("deptId") Long deptId);
public int deleteById(Long id);
public int insert(@Param("role") Role role);
public int updateRoleName(@Param("roleId") Long roleId, @Param("roleName") String name);
}
4.3 RoleMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper SYSTEM "myorm.dtd">
<mapper namespace="com.test.mapper.RoleMapper">
<select id="getRoleById" parameterType="java.lang.Long" resultType ="com.test.entry.Role">
select * from sys_role where role_id = #{id}
</select>
<select id="getRoleByIdAndDeptId" resultType ="com.test.entry.Role">
select * from sys_role where role_id = #{id} and dept_id = #{deptId}
</select>
<delete id="deleteById" parameterType="java.lang.Long">
delete from sys_role where role_id = #{id}
</delete>
<insert id="insert">
insert into sys_role (role_id, role_name, remark, dept_id, create_time)
values (#{role.roleId}, #{role.roleName}, #{role.remark}, #{role.deptId}, #{role.createTime})
</insert>
<update id="updateRoleName">
update sys_role set role_name = #{roleName} where role_id = #{roleId}
</update>
</mapper>
注意:@Param()中的value一定要和實體對象Role字段相同。
4.4 myorm.dtd 對mapperxml文檔的合法構建
<!ELEMENT mapper (select* | insert* | update* | delete* | sql*)+>
<!ELEMENT select (#PCDATA | select)*>
<!ELEMENT insert (#PCDATA)>
<!ELEMENT update (#PCDATA)>
<!ELEMENT delete (#PCDATA)>
<!ELEMENT sql (#PCDATA)>
<!ATTLIST mapper namespace CDATA #IMPLIED>
<!ATTLIST select
id CDATA #REQUIRED
parameterType CDATA #IMPLIED
resultType CDATA #IMPLIED
>
<!ATTLIST delete
id CDATA #REQUIRED
parameterMap CDATA #IMPLIED
parameterType CDATA #IMPLIED
>
<!ATTLIST insert
id CDATA #REQUIRED
parameterMap CDATA #IMPLIED
parameterType CDATA #IMPLIED
>
<!ATTLIST update
id CDATA #REQUIRED
parameterMap CDATA #IMPLIED
parameterType CDATA #IMPLIED
>
4.5 通過註解方式【優先使用註解,沒註解使用xml配置】
@Select("select * from sys_role where role_id = #{id}")
public Role selectRoleById(Long id);
核心代碼:
if (method.getAnnotations().length !=0 && method.getAnnotations().length > 1){
throw new RuntimeException("該方法上只能有一個註解");
}
if (method.getAnnotations().length == 1){
Function function = new Function();
String sql = "";
String sqlType = "";
if (method.isAnnotationPresent(Insert.class)){
Insert insert = method.getAnnotation(Insert.class);
sql = insert.value();
sqlType = "insert";
}else if (method.isAnnotationPresent(Delete.class)){
Delete insert = method.getAnnotation(Delete.class);
sql = insert.value();
sqlType = "delete";
}else if (method.isAnnotationPresent(Update.class)){
Update insert = method.getAnnotation(Update.class);
sql = insert.value();
sqlType = "update";
}else if (method.isAnnotationPresent(Select.class)){
Select insert = method.getAnnotation(Select.class);
sql = insert.value();
sqlType = "select";
}
function.setSql(sql);
function.setFunctionName(method.getName());
function.setParameterType("");
function.setSqlType(sqlType);
function.setResultType(method.getReturnType().getTypeName());
functionMap.put(method.getName(), function);
}