硬核手写简易mybatis框架

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: 硬核手写简易mybatis框架

简易框架功能介绍

搭建这个简易的框架是为了加深对mybatis的理解,功能不是全部实现的(也没有能力),所以这个简易的框架的功能只支持表字段都为varchar,pojo为String类型的,而且本框架只支持JDBC事务管理器,只支持非池化,功能的话只实现了插入,查询(单个数据不支持多个)。

创建模块导入相关pom依赖

使用dom4j去进行解析xml文件

1. <?xml version="1.0" encoding="UTF-8"?>
2. <project xmlns="http://maven.apache.org/POM/4.0.0"
3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5. <modelVersion>4.0.0</modelVersion>
6. 
7. <groupId>org.example</groupId>
8. <artifactId>mybatis-xml-dom4j</artifactId>
9. <version>1.0-SNAPSHOT</version>
10. <dependencies>
11. <!--dom4j依赖-->
12. <dependency>
13. <groupId>org.dom4j</groupId>
14. <artifactId>dom4j</artifactId>
15. <version>2.1.3</version>
16. </dependency>
17. <!--jaxen依赖-->
18. <dependency>
19. <groupId>jaxen</groupId>
20. <artifactId>jaxen</artifactId>
21. <version>1.2.0</version>
22. </dependency>
23. <!--junit依赖-->
24. <dependency>
25. <groupId>junit</groupId>
26. <artifactId>junit</artifactId>
27. <version>4.13.2</version>
28. <scope>test</scope>
29. </dependency>
30. </dependencies>
31. 
32. <properties>
33. <maven.compiler.source>17</maven.compiler.source>
34. <maven.compiler.target>17</maven.compiler.target>
35. </properties>
36. 
37. </project>

资源工具类

这个类用于读取指定配置文件的输入流,即读取resourse目录下的文件

1. /**
2.  * @author 风轻云淡
3.  */
4. public class Resource {
5. /**
6.      * 从类路径中获取配置文件输入输出流动
7.      */
8. public static InputStream getResourcesAsStream(String path){
9. return Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
10.     }
11. }

sqlSessionFactoryBuilder工厂构造类

读取batis核心配置文件,工具SqlSessionFactory对象

build方法主要负责功能解析配置文件:

                                                       创建数据源对象

                                                       创建事物管理器对象

                                                        获取所有的SQL映射文件

1. /**
2.  * @author 风轻云淡
3.  */
4. public class SqlSessionFactoryBuilder {
5. public SqlSessionFactoryBuilder() {
6. 
7.     }
8. 
9. /**
10.      * 获取SqlSessionFactory对象
11.      * 读取batis核心配置文件,工具SqlSessionFactory对象
12.      * @param inputStream 指向核心配置文件的输入流动
13.      * @return
14.      */
15. public SqlSessionFactory build(InputStream inputStream){
16. /**
17.          * 主要负责功能解析配置文件
18.          *          创建数据源对象
19.          *          创建事物管理器对象
20.          *          获取所有的SQL映射文件
21.          *          封装到SqlSessionFactory对象中
22.          *
23.          */
24. return null;
25.     }
26. }

SqlSessionFactory设计和MappedStatement的编写

这个类应该包含:

一个属性为事务管理器,对应执行sql语句的MappedStatement对象

JDBCTransaction属性

Map<String, MappedStatement>属性

MappedStatement:

1. /**
2.  * @author 风轻云淡
3.  */
4. public class MapperStatement {
5. private  String sqlId;
6. private String resultType;
7. private  String sql;
8. private  String parameterType;
9. private  String sqlType;
10. 
11. public MapperStatement(String sqlId, String resultType, String sql, String parameterType, String sqlType) {
12. this.sqlId = sqlId;
13. this.resultType = resultType;
14. this.sql = sql;
15. this.parameterType = parameterType;
16. this.sqlType = sqlType;
17.     }
18. 
19. @Override
20. public String toString() {
21. return "MapperStatement{" +
22. "sqlId='" + sqlId + '\'' +
23. ", resultType='" + resultType + '\'' +
24. ", sql='" + sql + '\'' +
25. ", parameterType='" + parameterType + '\'' +
26. ", sqlType='" + sqlType + '\'' +
27. '}';
28.     }
29. 
30. public String getSqlId() {
31. return sqlId;
32.     }
33. 
34. public void setSqlId(String sqlId) {
35. this.sqlId = sqlId;
36.     }
37. 
38. public String getResultType() {
39. return resultType;
40.     }
41. 
42. public void setResultType(String resultType) {
43. this.resultType = resultType;
44.     }
45. 
46. public String getSql() {
47. return sql;
48.     }
49. 
50. public void setSql(String sql) {
51. this.sql = sql;
52.     }
53. 
54. public String getParameterType() {
55. return parameterType;
56.     }
57. 
58. public void setParameterType(String parameterType) {
59. this.parameterType = parameterType;
60.     }
61. 
62. public String getSqlType() {
63. return sqlType;
64.     }
65. 
66. public void setSqlType(String sqlType) {
67. this.sqlType = sqlType;
68.     }
69. 
70. 
71. }

JDBCTransaction设计

我们知道mybatis的事务管理器类型有只能填MANAGED或者JDBC,在本框架中我们只实现最简单的JDBC事务管理器

● transactionManager:配置事务管理器

 ○ type属性:指定事务管理器具体使用什么方式,可选值包括两个

   ■ JDBC:使用JDBC原生的事务管理机制。底层原理:事务开启conn.setAutoCommit(false); ...处理业务...事务提交conn.commit();

   ■ MANAGED:交给其它容器来管理事务,比如WebLogic、JBOSS等。如果没有管理事务的容器,则没有事务。没有事务的含义:只要执行一条DML语句,则提交一次。

事务管理器最好是定义一个接口,然后每一个具体的事务管理器都实现这个接口。

1. /**
2.  * @author 风轻云淡
3.  */
4. public class JDBCTransaction implements TransactionManager{
5. /**
6.      * 数据库连接对象
7.      */
8. private  Connection connection;
9. 
10. /**
11.      * 数据源对象
12.      */
13. private DataSource dataSource;
14. 
15. /**
16.      * 自动提交标记
17.      * true:自动提交
18.      * false:不自动提交
19.      */
20. private  boolean autoCommit;
21. 
22. /**
23.      * 构造事务管理器对象
24.      */
25. public JDBCTransaction( DataSource dataSource,Connection connection) {
26. this.connection = connection;
27. this.dataSource = dataSource;
28. 
29.     }
30. 
31. @Override
32. public void commit() {
33. try {
34.             connection.commit();
35.         }catch (Exception e){
36.             e.printStackTrace();
37.         }
38.     }
39. 
40. @Override
41. public void rollback() {
42. try {
43.             connection.rollback();
44.         } catch (SQLException throwables) {
45.             throwables.printStackTrace();
46.         }
47.     }
48. 
49. @Override
50. public void close() {
51. try {
52.             connection.close();
53.         } catch (SQLException throwables) {
54.             throwables.printStackTrace();
55.         }
56.     }
57. 
58. @Override
59. public void openConnection() {
60. try {
61. Connection connection = dataSource.getConnection();
62. this.connection.setAutoCommit(this.autoCommit);
63.         } catch (SQLException throwables) {
64.             throwables.printStackTrace();
65.         }
66. 
67.     }
68. 
69. @Override
70. public Connection getConnection() {
71. return connection;
72.     }
73. }

JDBC事务管理器实现类

1. /**
2.  * @author 风轻云淡
3.  */
4. public class JDBCTransaction implements TransactionManager{
5. @Override
6. public void commit() {
7. 
8.     }
9. 
10. @Override
11. public void rollback() {
12. 
13.     }
14. 
15. @Override
16. public void close() {
17. 
18.     }
19. 
20. @Override
21. public void openConnection() {
22. 
23.     }
24. 
25. @Override
26. public Connection getConnection() {
27. return null;
28.     }
29. }

UNPOOLEDDataSource数据源类设计

unpool即在本框架中不使用数据库连接池技术实现

1. /**
2.  * @author 风轻云淡
3.  */
4. public class UNPOOLEDDataSource implements  javax.sql.DataSource{
5. private String url;
6. private String username;
7. private String password;
8. 
9. public UNPOOLEDDataSource(String driver,String url,String username,String password){
10. try {
11.             Class.forName(driver);
12. 
13.         }catch (Exception e){
14.             e.printStackTrace();
15.         }
16. this.url=url;
17. this.username=username;
18. this.password=password;
19.     }
20. 
21. 
22. @Override
23. public Connection getConnection() throws SQLException {
24. return DriverManager.getConnection(url,username,password);
25.     }
26. 
27. @Override
28. public Connection getConnection(String username, String password) throws SQLException {
29. return null;
30.     }
31. 
32. @Override
33. public PrintWriter getLogWriter() throws SQLException {
34. return null;
35.     }
36. 
37. @Override
38. public void setLogWriter(PrintWriter out) throws SQLException {
39. 
40.     }
41. 
42. @Override
43. public void setLoginTimeout(int seconds) throws SQLException {
44. 
45.     }
46. 
47. @Override
48. public int getLoginTimeout() throws SQLException {
49. return 0;
50.     }
51. 
52. @Override
53. public Logger getParentLogger() throws SQLFeatureNotSupportedException {
54. return null;
55.     }
56. 
57. @Override
58. public <T> T unwrap(Class<T> iface) throws SQLException {
59. return null;
60.     }
61. 
62. @Override
63. public boolean isWrapperFor(Class<?> iface) throws SQLException {
64. return false;
65.     }
66. }

SqlSessionFactory类完善

1. /**
2.  * @author 风轻云淡
3.  */
4. public class SqlSessionFactory {
5. private  TransactionManager transactionManager;
6. private Map<String,MapperStatement> mapperStatements;
7. 
8. public SqlSessionFactory(TransactionManager transactionManager, Map<String, MapperStatement> mapperStatements) {
9. this.transactionManager = transactionManager;
10. this.mapperStatements = mapperStatements;
11.     }
12. 
13. public TransactionManager getTransactionManager() {
14. return transactionManager;
15.     }
16. 
17. public void setTransactionManager(TransactionManager transactionManager) {
18. this.transactionManager = transactionManager;
19.     }
20. 
21. public Map<String, MapperStatement> getMapperStatements() {
22. return mapperStatements;
23.     }
24. 
25. public void setMapperStatements(Map<String, MapperStatement> mapperStatements) {
26. this.mapperStatements = mapperStatements;
27.     }
28. }

SqlSessionFactoryBuilder中的build方法编写

1. /**
2.  * @author 风轻云淡
3.  */
4. public class SqlSessionFactoryBuilder {
5. public SqlSessionFactoryBuilder() {
6. 
7.     }
8. 
9. /**
10.      * 获取SqlSessionFactory对象
11.      * 读取batis核心配置文件,工具SqlSessionFactory对象
12.      * @param inputStream 指向核心配置文件的输入流动
13.      * @return
14.      */
15. public SqlSessionFactory build(InputStream inputStream) throws DocumentException {
16. /**
17.          * 主要负责功能解析配置文件
18.          *          创建数据源对象
19.          *          创建事物管理器对象
20.          *          获取所有的SQL映射文件
21.          *          封装到SqlSessionFactory对象中
22.          *
23.          */
24. Document document = new SAXReader().read(inputStream);
25. Element environmentsElt = (Element) document.selectSingleNode("/configuration/environments");
26. String defaultEnv = environmentsElt.attributeValue("default");
27. //解析文件得出数据源对象
28. Element dataSourceElt = environmentsElt.element("dataSource");
29.         DataSource dataSource= getDataSource(dataSourceElt);
30. //解析文件得出事务管理器对象
31. Element transactionManagerElt = environmentsElt.element("transactionManager");
32. TransactionManager transactionManager =gettransactionManager(transactionManagerElt,dataSource);
33. //解析文件得出sql映射对象
34.         Element mapperElt=environmentsElt.element("mappers");
35.         Map<String,MapperStatement> mapperStatementMap =getMapperStatements(mapperElt);
36. SqlSessionFactory sqlSessionFactory = new SqlSessionFactory(transactionManager, mapperStatementMap);
37. return sqlSessionFactory;
38.     }
39. 
40. private Map<String, MapperStatement> getMapperStatements(Element mapperElt) {
41.         Map<String,MapperStatement> mapperStatements=new HashMap<>();
42. try {
43. String resource = mapperElt.attributeValue("resource");
44. SAXReader saxReader = new SAXReader();
45. Document document = saxReader.read(Resource.getResourcesAsStream(resource));
46. Element mapper = (Element) document.selectSingleNode("/mapper");
47. String namespace = mapper.attributeValue("namespace");
48.             mapper.elements().forEach(item->{
49. String sqlId = item.attributeValue("id");
50. String sql = item.getTextTrim();
51. String parameterType = item.attributeValue("parameterType");
52. String resultType = item.attributeValue("resultType");
53. String sqlType = item.getName().toLowerCase();
54. //封装对象
55. MapperStatement mapperStatement = new MapperStatement(sqlId, resultType, sql, parameterType, sqlType);
56.                 mapperStatements.put(namespace+"."+sqlId,mapperStatement);
57. 
58.             });
59. 
60.         }catch (Exception e){
61.             e.printStackTrace();
62.         }
63. return mapperStatements;
64.     }
65. 
66. private TransactionManager gettransactionManager(Element transactionManagerElt, DataSource dataSource) {
67. String type = transactionManagerElt.attributeValue("type").toUpperCase();
68.         TransactionManager transactionManager=null;
69. if("JDBC".equals(type)){
70.             transactionManager=new JDBCTransaction(dataSource,false);
71.         }else{
72. try {
73. throw  new Exception("本框架只支持JDBC事务管理");
74.             } catch (Exception e) {
75.                 e.printStackTrace();
76.             }
77.         };
78. return transactionManager;
79.     }
80. 
81. private DataSource getDataSource(Element dataSourceElt)  {
82. //获取所有数据源配置
83.         Map<String ,String> dataSourceMap=new HashMap<>();
84.         dataSourceElt.elements().forEach(item->{
85.             dataSourceMap.put(item.attributeValue("name"),item.attributeValue("value"));
86.         });
87. String dataSourceType = dataSourceElt.attributeValue("type").toUpperCase();
88.         DataSource dataSource=null;
89. if("UNPOOLED".equals(dataSourceType)){
90.             dataSource=new UNPOOLEDDataSource(dataSourceMap.get("driver"),
91.                     dataSourceMap.get("url"),
92.                     dataSourceMap.get("username"),
93.                     dataSourceMap.get("password"));
94.         }else{
95. try {
96. throw new Exception("本框架只实现了UNPOOLED");
97.             } catch (Exception e) {
98.                 e.printStackTrace();
99.             }
100.         }
101. return dataSource;
102.     }
103. }

SqlSession编写

1. public class SqlSession {
2.     TransactionManager transactionManager;
3.     Map<String, MapperStatement> mapperStatements;
4. 
5. public SqlSession(TransactionManager transactionManager, Map<String, MapperStatement> mapperStatements) {
6. this.transactionManager = transactionManager;
7. this.mapperStatements = mapperStatements;
8.     }
9. public void commit(){
10. try {
11.             transactionManager.getConnection().commit();
12.         } catch (SQLException e) {
13. throw new RuntimeException(e);
14.         }
15.     }
16. 
17. public void rollback(){
18. try {
19.             transactionManager.getConnection().rollback();
20.         } catch (SQLException e) {
21. throw new RuntimeException(e);
22.         }
23.     }
24. 
25. public void close(){
26. try {
27.             transactionManager.getConnection().close();
28.         } catch (SQLException e) {
29. throw new RuntimeException(e);
30.         }
31.     }
32. }

在SqlSessionFactory中添加openSession方法

1. public SqlSession openSession(){
2.     transactionManager.openConnection();
3. SqlSession sqlSession = new SqlSession(transactionManager, mappedStatements);
4. return sqlSession;
5. }

编写SqlSession类中的insert方法

1. /**
2.      * 插入数据
3.      *
4.      * @param sqlId 要执行的sqlId
5.      * @param obj   插入的数据
6.      * @return
7.      */
8. public int insert(String sqlId, Object obj) {
9. MapperStatement godMappedStatement = mapperStatements.get(sqlId);
10. Connection connection = transactionManager.getConnection();
11. // 获取sql语句
12. // insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
13. String godbatisSql = godMappedStatement.getSql();
14. // insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,?,?,?,?,?)
15. String sql = godbatisSql.replaceAll("#\\{[a-zA-Z0-9_\\$]*}", "?");
16. 
17. // 重点一步
18.         Map<Integer, String> map = new HashMap<>();
19. int index = 1;
20. while (godbatisSql.indexOf("#") >= 0) {
21. int beginIndex = godbatisSql.indexOf("#") + 2;
22. int endIndex = godbatisSql.indexOf("}");
23.             map.put(index++, godbatisSql.substring(beginIndex, endIndex).trim());
24.             godbatisSql = godbatisSql.substring(endIndex + 1);
25.         }
26. 
27. final PreparedStatement ps;
28. try {
29.             ps = connection.prepareStatement(sql);
30. 
31. // 给?赋值
32.             map.forEach((k, v) -> {
33. try {
34. // 获取java实体类的get方法名
35. String getMethodName = "get" + v.toUpperCase().charAt(0) + v.substring(1);
36. Method getMethod = obj.getClass().getDeclaredMethod(getMethodName);
37.                     ps.setString(k, getMethod.invoke(obj).toString());
38.                 } catch (Exception e) {
39. throw new RuntimeException(e);
40.                 }
41.             });
42. int count = ps.executeUpdate();
43.             ps.close();
44. return count;
45.         } catch (Exception e) {
46. throw new RuntimeException(e);
47.         }
48.     }

编写SqlSession类中的selectOne方法

1. /**
2.      * 查询一个对象
3.      * @param sqlId
4.      * @param parameterObj
5.      * @return
6.      */
7. public Object selectOne(String sqlId, Object parameterObj){
8. MapperStatement godMappedStatement = mapperStatements.get(sqlId);
9. Connection connection = transactionManager.getConnection();
10. // 获取sql语句
11. String godbatisSql = godMappedStatement.getSql();
12. String sql = godbatisSql.replaceAll("#\\{[a-zA-Z0-9_\\$]*}", "?");
13. // 执行sql
14. PreparedStatement ps = null;
15. ResultSet rs = null;
16. Object obj = null;
17. try {
18.             ps = connection.prepareStatement(sql);
19.             ps.setString(1, parameterObj.toString());
20.             rs = ps.executeQuery();
21. if (rs.next()) {
22. // 将结果集封装对象,通过反射
23. String resultType = godMappedStatement.getResultType();
24.                 Class<?> aClass = Class.forName(resultType);
25.                 Constructor<?> con = aClass.getDeclaredConstructor();
26.                 obj = con.newInstance();
27. // 给对象obj属性赋值
28. ResultSetMetaData rsmd = rs.getMetaData();
29. int columnCount = rsmd.getColumnCount();
30. for (int i = 1; i <= columnCount; i++) {
31. String columnName = rsmd.getColumnName(i);
32. String setMethodName = "set" + columnName.toUpperCase().charAt(0) + columnName.substring(1);
33. Method setMethod = aClass.getDeclaredMethod(setMethodName, aClass.getDeclaredField(columnName).getType());
34.                     setMethod.invoke(obj, rs.getString(columnName));
35.                 }
36.             }
37.         } catch (Exception e) {
38. throw new RuntimeException(e);
39.         } finally {
40. if (rs != null) {
41. try {
42.                     rs.close();
43.                 } catch (SQLException e) {
44. throw new RuntimeException(e);
45.                 }
46.             }
47. try {
48.                 ps.close();
49.             } catch (SQLException e) {
50. throw new RuntimeException(e);
51.             }
52.         }
53. return obj;
54.     }


相关文章
|
19天前
|
SQL Java 数据库连接
对Spring、SpringMVC、MyBatis框架的介绍与解释
Spring 框架提供了全面的基础设施支持,Spring MVC 专注于 Web 层的开发,而 MyBatis 则是一个高效的持久层框架。这三个框架结合使用,可以显著提升 Java 企业级应用的开发效率和质量。通过理解它们的核心特性和使用方法,开发者可以更好地构建和维护复杂的应用程序。
108 29
|
3月前
|
SQL Java 数据库连接
持久层框架MyBatisPlus
持久层框架MyBatisPlus
75 1
持久层框架MyBatisPlus
|
4月前
|
缓存 Cloud Native 安全
探索阿里巴巴新型ORM框架:超越MybatisPlus?
【10月更文挑战第9天】在Java开发领域,Mybatis及其增强工具MybatisPlus长期占据着ORM(对象关系映射)技术的主导地位。然而,随着技术的发展,阿里巴巴集团推出了一种新型ORM框架,旨在提供更高效、更简洁的开发体验。本文将对这一新型ORM框架进行探索,分析其特性,并与MybatisPlus进行比较。
165 0
|
6月前
|
SQL Java 数据库连接
【Java 第十三篇章】MyBatis 框架介绍
MyBatis 原名 iBATIS,2001 年由 Clinton Begin 创建,以其简易灵活著称。2010 年更名以重塑品牌形象。MyBatis 通过 SQL 映射文件将 SQL 语句与 Java 代码分离,支持编写原生 SQL 并与方法映射。具备对象关系映射功能,简化数据库记录处理。支持动态 SQL 构建,灵活应对不同查询条件。内置缓存机制,提升查询效率。相比全功能 ORM,MyBatis 提供更高 SQL 控制度和更好的维护性,并易于与 Spring 等框架集成,广泛应用于 Java 数据访问层。
58 0
|
6月前
|
Java 数据库连接 Spring
后端框架入门超详细 三部曲 Spring 、SpringMVC、Mybatis、SSM框架整合案例 【爆肝整理五万字】
文章是关于Spring、SpringMVC、Mybatis三个后端框架的超详细入门教程,包括基础知识讲解、代码案例及SSM框架整合的实战应用,旨在帮助读者全面理解并掌握这些框架的使用。
后端框架入门超详细 三部曲 Spring 、SpringMVC、Mybatis、SSM框架整合案例 【爆肝整理五万字】
|
6月前
|
druid Java 数据库连接
SpringBoot项目整合MybatisPlus持久层框架+Druid数据库连接池,以及实现增删改查功能
SpringBoot项目整合MybatisPlus和Druid数据库连接池,实现基本的增删改查功能。
482 0
|
6月前
|
SQL Java 数据库连接
后端框架的学习----mybatis框架(5、分页)
这篇文章介绍了如何在MyBatis框架中实现分页功能,包括使用SQL的`limit`语句进行分页和利用MyBatis的`RowBounds`对象进行分页的方法。
|
6月前
|
SQL Java 数据库连接
后端框架的学习----mybatis框架(7、使用注解开发)
这篇文章讲述了如何使用MyBatis框架的注解方式进行开发,包括在接口上使用注解定义SQL语句,并通过动态代理实现对数据库的增删改查操作,同时强调了接口需要在核心配置文件中注册绑定。
|
6月前
|
Java 数据库连接 mybatis
mybatis框架图
文章介绍了MyBatis框架的起源、发展和其作为持久层框架的功能,提供了MyBatis的框架图以帮助理解其结构和组件。
mybatis框架图
|
6月前
|
Java 数据库连接 mybatis
后端框架的学习----mybatis框架(9、多对一处理和一对多处理)
这篇文章介绍了在MyBatis框架中如何处理多对一和一对多的关联查询,通过定义`<resultMap>`和使用`<association>`与`<collection>`元素来实现对象间的关联映射。