• 手写Mybatis


    Mybatis核心配置文件就是为了配置Configration

    因此要首先会解析Mybatis核心配置文件

    首先使用dom4J解析Mybatis核心配置文件

    新建模块演示dom4j解析.xml

    目录放错了  无所谓

    引入依赖

    从原来项目可以拷贝过来

    就些简单配置就好

    解析核心配置文件和解析xxxMapper.xml映射文件代码

    1. import org.dom4j.Document;
    2. import org.dom4j.DocumentException;
    3. import org.dom4j.Element;
    4. import org.dom4j.Node;
    5. import org.dom4j.io.SAXReader;
    6. import org.junit.Test;
    7. import java.io.InputStream;
    8. import java.util.List;
    9. /**
    10. * @author hrui
    11. * @date 2023/9/10 18:24
    12. */
    13. public class ParseXMLByDom4JTest {
    14. //解析Mapper映射文件
    15. @Test
    16. public void testParseSqlMapperXML() throws DocumentException {
    17. //创建SAXReader对象
    18. SAXReader reader=new SAXReader();
    19. //获取输入流(将resources目录下的mybatis-config1.xml转输入流)
    20. InputStream inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream("mapper/CarMapperABC.xml");
    21. //读XML文件
    22. Document document=reader.read(inputStream);
    23. String xpath="/mapper";
    24. Element mapper =(Element) document.selectSingleNode(xpath);
    25. String namespace = mapper.attributeValue("namespace");
    26. System.out.println(namespace);//aaa
    27. //获取mapper节点下所有子节点
    28. List<Element> elements = mapper.elements();
    29. elements.forEach(e->{
    30. //获取sqlId
    31. String id = e.attributeValue("id");
    32. //获取resultType 没有返回null
    33. System.out.println(id);
    34. //获取标签中的sql语句,取出前后空白
    35. String sql = e.getTextTrim();
    36. System.out.println(sql);//insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
    37. //现在是:insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})
    38. //内部肯定使用JDBC:insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,?,?,?,?,?)
    39. //转换
    40. String newSql = sql.replaceAll("#\\{[0-9A-Za-z_$]*}", "?");//使用正则替换
    41. System.out.println(newSql);//insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,?,?,?,?,?)
    42. });
    43. }
    44. //解析核心配置文件
    45. @Test
    46. public void testParseMybatisConfigXML() throws DocumentException {
    47. //创建SAXReader对象
    48. SAXReader reader=new SAXReader();
    49. //获取输入流(将resources目录下的mybatis-config1.xml转输入流)
    50. InputStream inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream("mybatis-config1.xml");
    51. //读XML文件
    52. Document document=reader.read(inputStream);
    53. //System.out.println(document);
    54. //获取根标签
    55. Element root = document.getRootElement();
    56. //System.out.println(root.getName());//configuration
    57. //获取跟标签后肯定是去获取环境 environments 获取里面的default数据库id
    58. //获取默认的环境id
    59. //xpath是做标签路径匹配的.能够让我们快速定位XML文件中的元素
    60. //以下的xpath:从跟下开始找configuration,然后找configuration标签下的子标签environments
    61. String xpath="/configuration/environments";
    62. Element element = (Element)document.selectSingleNode(xpath);
    63. //System.out.println(element);
    64. //获取属性的值 默认环境id
    65. String aDefaultEnvivironmentId = element.attributeValue("default");
    66. //System.out.println("默认环境id是:"+aDefaultEnvivironmentId);//development
    67. //去找environment的 id属性,然后和默认环境id比较,确定默认使用哪个数据库
    68. //下面是xpath的写法 意思找
    69. xpath="/configuration/environments/environment[@id='"+aDefaultEnvivironmentId+"']";
    70. Element enviroment =(Element) document.selectSingleNode(xpath);
    71. //System.out.println(enviroment.getName());environment
    72. //获取environment节点下的transactionManager
    73. Element transactionManager = enviroment.element("transactionManager");
    74. String transactionType = transactionManager.attributeValue("type");
    75. //System.out.println("事务管理器的类型:"+transactionType);//获取事务管理器类型----->JDBC
    76. //接着获取datasource节点
    77. Element datasource = enviroment.element("dataSource");
    78. String dataSourcetype = datasource.attributeValue("type");
    79. System.out.println("数据源的类型:"+dataSourcetype);//POOLED
    80. //获取dataSource下的所有子节点
    81. List<Element> propertyElements = datasource.elements();
    82. //遍历
    83. propertyElements.forEach(e->{
    84. String name = e.attributeValue("name");
    85. String value = e.attributeValue("value");
    86. System.out.println("name="+name+",value="+value);
    87. });
    88. //获取所有的mapper标签
    89. //如果你不想从跟下开始获取,而是想从任意位置开始,获取某个标签,xpath可以这样写
    90. xpath="//mapper";// 两个//开始
    91. List<Node> mappers = document.selectNodes(xpath);
    92. //遍历
    93. mappers.forEach(n->{
    94. Element e=(Element)n;
    95. String resource = e.attributeValue("resource");
    96. System.out.println(resource);
    97. });
    98. }
    99. }

    新建module 

    引入依赖

    可以回顾下标准写法

    逆推下

    Resources

    SqlSessionFactoryBuilder

    SqlSessionFactory

    transaction  

    SqlSession

    SQL Mapper

    思路:1.Resources用来加载核心配置文件,返回一个InputStream流,

    2.SqlSessionFactoryBuilder里有个build方法,该方法用来返回一个SqlSessionFactory对象

    这里要考虑,SqlSessionFactory里有些什么,用来做什么.

    那么这样就明了了,build方法用来解析核心配置文件,用以给SqlSessionFactory里的属性赋值,而属性有哪些,就是上面这些呗(事务管理器,JDBC连接需要的driver,url,username,password)

    另外

    和映射文件

    是否考虑用一个容器Map存放,key为sql的id   value是其他

    将这个对象也封装到SqlSessionFactory中

    这个对象中该有哪些属性:暂时放sql语句和resultType  当然实际放的不只这两个  获取不到就是null

    SqlSessionFactory中还需要一个事务管理器,这个事务管理器可以是JDBC也可以是MANAGED,那么可以定义为接口,另外定义两个具体的实现  这里使用JDBC事务管理器

    而我们定义了事务管理器之后,事务管理器需要搞定的就三个方法,commit,rollback,close

    但是这三个方法需要连接对象,而要获取连接对象可以定义个数据源

    在核心配置文件中,数据源有三个选项,分别是POOLED   UNPOOLED  JNDI

    那好办,定义为接口呗

    这里有个JDK规范,不管你是POOLED   UNPOOLED  JNDI所有的数据源都需要实现JDK里的DataSource接口  那么接口也不用定义了 直接写三个实现类  这里使用UNPOOLED 不使用连接池

    那么在实现类里需要driver url username password属性

    然后又个SqlSession对象

    里面又insert方法   xxx 方法  需要用到什么,再解决

    基本思路就是这样

    整体结构

    1.Resources

    1. package com.gmybatis.utils;
    2. import java.io.InputStream;
    3. /**
    4. * 工具类
    5. * 用于"类路径"中资源的加载
    6. * @author hrui
    7. * @date 2023/9/10 20:25
    8. */
    9. public class Resources {
    10. //工具类建议构造方法私有化,因为工具类一般方法都是静态的,是种编程习惯
    11. public Resources() {
    12. }
    13. /**
    14. * 用于"类路径"种加载资源
    15. * @param resource
    16. * @return
    17. */
    18. public static InputStream getResourceAsStream(String resource){
    19. return ClassLoader.getSystemClassLoader().getResourceAsStream(resource);
    20. }
    21. }

    2.SqlSessionFactoryBuilder   构建器对象

    1. package com.gmybatis.core;
    2. import com.gmybatis.utils.Resources;
    3. import jdk.nashorn.internal.ir.ReturnNode;
    4. import org.dom4j.Document;
    5. import org.dom4j.DocumentException;
    6. import org.dom4j.Element;
    7. import org.dom4j.Node;
    8. import org.dom4j.io.SAXReader;
    9. import javax.sql.DataSource;
    10. import java.io.InputStream;
    11. import java.util.ArrayList;
    12. import java.util.HashMap;
    13. import java.util.List;
    14. import java.util.Map;
    15. /**
    16. * SqlSessionFactory的构建器对象
    17. * 通过SqlSessionFactoryBuilder的build方法来解析核心配置文件,
    18. * 然后创建SqlSessionFactory对象
    19. * @author hrui
    20. * @date 2023/9/10 20:31
    21. */
    22. public class SqlSessionFactoryBuilder {
    23. public SqlSessionFactoryBuilder() {
    24. }
    25. /**
    26. * 解析核心配置文件,来构建SqlSessionFactory
    27. * @param in
    28. * @return
    29. */
    30. public SqlSessionFactory build(InputStream in){
    31. SqlSessionFactory sqlSessionFactory=null;
    32. try {
    33. //解析核心配置文件
    34. //创建SAXReader对象
    35. SAXReader reader=new SAXReader();
    36. //读XML文件
    37. Document document=reader.read(in);
    38. //获取environments
    39. Element environments =(Element) document.selectSingleNode("/configuration/environments");
    40. //获取default属性值
    41. String defaultId = environments.attributeValue("default");
    42. //拿匹配的环境节点
    43. Element environment = (Element)document.selectSingleNode("/configuration/environments/environment[@id='"+defaultId+"']");
    44. //获取transactionManager
    45. Element transactionManagerEle = environment.element("transactionManager");
    46. //获取dataSource
    47. Element dataSourceEle = environment.element("dataSource");
    48. //获取mapper
    49. List<Node> mapperList = document.selectNodes("//mapper");//获取整个配置文件中所有的mapper标签
    50. //用于封装所有mappers里面的mapper的路径
    51. List<String> sqlMapperXMLPathList=new ArrayList<>();
    52. mapperList.forEach(n->{
    53. Element e=(Element) n;
    54. String resource = e.attributeValue("resource");
    55. sqlMapperXMLPathList.add(resource);
    56. });
    57. //获取数据源对象
    58. DataSource dataSource=getDataSource(dataSourceEle);
    59. //定义事务管理器
    60. Transaction transaction=getTransaction(transactionManagerEle,dataSource);
    61. //key是namespase+sql的id
    62. Map<String,MappedStatement> MappedStatements=getMappedStatements(sqlMapperXMLPathList);
    63. //解析完成之后,构建出SqlSessionFactory对象
    64. sqlSessionFactory=new SqlSessionFactory(transaction,MappedStatements);
    65. } catch (Exception e) {
    66. e.printStackTrace();
    67. }
    68. return sqlSessionFactory;
    69. }
    70. private Map<String, MappedStatement> getMappedStatements(List<String> sqlMapperXMLPathList) {
    71. Map<String,MappedStatement> map=new HashMap<>();
    72. sqlMapperXMLPathList.forEach(path->{
    73. try {
    74. //创建SAXReader对象
    75. SAXReader reader=new SAXReader();
    76. //读XXXMapper.XML映射文件
    77. Document document=reader.read(Resources.getResourceAsStream(path));
    78. //解析映射文件
    79. Element mapper = (Element)document.selectSingleNode("mapper");//带不带/都可以
    80. String namespace = mapper.attributeValue("namespace");
    81. List<Element> elements = mapper.elements();
    82. elements.forEach(e->{
    83. String id = e.attributeValue("id");
    84. //namespase+id
    85. String sqlId=namespace+"."+id;
    86. String resultType = e.attributeValue("resultType");
    87. String sqlContent = e.getTextTrim();
    88. MappedStatement mappedStatement=new MappedStatement(sqlContent,resultType);
    89. map.put(sqlId,mappedStatement);
    90. });
    91. } catch (DocumentException e) {
    92. e.printStackTrace();
    93. }
    94. });
    95. return map;
    96. }
    97. private DataSource getDataSource(Element dataSourceEle) {
    98. Map<String,String> map=new HashMap<>();
    99. //获取节点下所有property
    100. List<Element> propertys = dataSourceEle.elements("property");
    101. propertys.forEach(e->{
    102. String name = e.attributeValue("name");
    103. String value = e.attributeValue("value");
    104. map.put(name,value);
    105. });
    106. DataSource dataSource=null;
    107. //type 可能是 POOLED UNPOOLED JNDI
    108. String type = dataSourceEle.attributeValue("type");
    109. // if(type.equalsIgnoreCase("POOLED")){ //这里简易定义常量类
    110. //
    111. // }
    112. if(type.equalsIgnoreCase(Const.POOLED_DATASOURCE)){
    113. dataSource=new POOLEDDataSource();
    114. }
    115. if(type.equalsIgnoreCase(Const.UN_POOLED_DATASOURCE)){//只对这个做了实现
    116. dataSource=new UNPOOLEDDataSource(map.get("driver"),map.get("url"),map.get("username"),map.get("password"));
    117. }
    118. if(type.equalsIgnoreCase(Const.JNDI_DATASOURCE)){
    119. dataSource=new JNDIDataSource();
    120. }
    121. return dataSource;
    122. }
    123. private Transaction getTransaction(Element transactionManager, DataSource dataSource) {
    124. Transaction transaction=null;
    125. String type = transactionManager.attributeValue("type");
    126. if(type.equalsIgnoreCase(Const.JDBC_TRANSACTION)){
    127. transaction=new JDBCTransaction(dataSource,false );//只对JDBCTransaction做了实现
    128. }
    129. if(type.equalsIgnoreCase(Const.MANAGED_TRANSACTION)){
    130. transaction=new MANAGEDTransaction();
    131. }
    132. return transaction;
    133. }
    134. }

    3.SqlSessionFactory

    1. package com.gmybatis.core;
    2. import java.util.Map;
    3. /**
    4. *SqlSessionFactory对象,一个数据库对应一个SqlSessionFactory对象
    5. * 通过SqlSessionFactory对象可以获得SqlSession对象(开启会话)
    6. * 一个SqlSessionFactory对象可以开启多个SqlSession会话
    7. * @author hrui
    8. * @date 2023/9/10 20:34
    9. */
    10. public class SqlSessionFactory {
    11. //事务管理器 可以是JDBC:原生JDBC事务 也可以是MANAGED:交容器管理,比如Spring 可以灵活切换建议定义为接口
    12. private Transaction transaction;
    13. //数据源属性 因为已经在事务管理器里定义了数据源,因此这里不需要定义 可以通过事务管理器来获取
    14. private Map<String,MappedStatement> mappedStatementMap;
    15. public SqlSessionFactory() {
    16. }
    17. public SqlSessionFactory(Transaction transaction, Map<String, MappedStatement> mappedStatementMap) {
    18. this.transaction = transaction;
    19. this.mappedStatementMap = mappedStatementMap;
    20. }
    21. public Transaction getTransaction() {
    22. return transaction;
    23. }
    24. public void setTransaction(Transaction transaction) {
    25. this.transaction = transaction;
    26. }
    27. public Map<String, MappedStatement> getMappedStatementMap() {
    28. return mappedStatementMap;
    29. }
    30. public void setMappedStatementMap(Map<String, MappedStatement> mappedStatementMap) {
    31. this.mappedStatementMap = mappedStatementMap;
    32. }
    33. // public SqlSession openSession(boolean flag){
    34. // return null;
    35. // }
    36. }

    Transaction接口及实现类,这里只实现了JDBCTransaction

    1. package com.gmybatis.core;
    2. import java.sql.Connection;
    3. /**
    4. * 事务管理器接口,所有的事务管理器都应该实现该接口
    5. * JDBC事务管理器,MANAGED事务管理器都应该实现这个接口
    6. * 提供控制事务的方法
    7. * @author hrui
    8. * @date 2023/9/10 21:14
    9. */
    10. public interface Transaction {
    11. //提交事务
    12. void commit();
    13. //回滚事务
    14. void rollback();
    15. //关闭事务
    16. void close();
    17. /**
    18. * 是否需要其他方法后续再看
    19. * 真正开启数据库连接
    20. */
    21. void openConnection();
    22. Connection getConnection();
    23. }

    JDBCTransaction

    1. package com.gmybatis.core;
    2. import javax.sql.DataSource;
    3. import java.sql.Connection;
    4. import java.sql.SQLException;
    5. /**
    6. * JDBC事务管理器
    7. * @author hrui
    8. * @date 2023/9/10 21:19
    9. */
    10. public class JDBCTransaction implements Transaction{
    11. //数据源属性
    12. private DataSource dataSource;
    13. /**
    14. * 自动提交标志
    15. * true为自动提交
    16. * false为不自动提交
    17. */
    18. private Boolean aotoCommit;
    19. private Connection connection;
    20. /**
    21. * 用于外界获取Connection
    22. * 外界用的Connection对象 必须和事务管理器的是同一个
    23. * 这样才可以在事务管理器里 commit rollback closed
    24. * @return
    25. */
    26. @Override
    27. public Connection getConnection() {
    28. return connection;
    29. }
    30. //用于给属性connection赋值 只要事务管理器不换 连接就是同一个连接、
    31. @Override
    32. public void openConnection(){
    33. if(connection==null){
    34. try {
    35. connection=dataSource.getConnection();
    36. } catch (SQLException e) {
    37. e.printStackTrace();
    38. }
    39. }
    40. }
    41. public JDBCTransaction(DataSource dataSource, Boolean aotoCommit) {
    42. this.dataSource = dataSource;
    43. this.aotoCommit = aotoCommit;
    44. }
    45. @Override
    46. public void commit() {
    47. //控制事务的时候需要调用JDBC里的连接对象 需要数据源
    48. try {
    49. connection.commit();
    50. } catch (SQLException e) {
    51. e.printStackTrace();
    52. }
    53. }
    54. @Override
    55. public void rollback() {
    56. try {
    57. connection.rollback();
    58. } catch (SQLException e) {
    59. e.printStackTrace();
    60. }
    61. }
    62. @Override
    63. public void close() {
    64. try {
    65. connection.commit();
    66. } catch (SQLException e) {
    67. e.printStackTrace();
    68. }
    69. }
    70. }

    MANAGEDTransaction

    1. package com.gmybatis.core;
    2. import java.sql.Connection;
    3. /**
    4. * MANAGED事务管理器
    5. * @author hrui
    6. * @date 2023/9/10 21:19
    7. */
    8. public class MANAGEDTransaction implements Transaction{
    9. @Override
    10. public void commit() {
    11. }
    12. @Override
    13. public void rollback() {
    14. }
    15. @Override
    16. public void close() {
    17. }
    18. @Override
    19. public void openConnection() {
    20. }
    21. @Override
    22. public Connection getConnection() {
    23. return null;
    24. }
    25. }

    实现DataSource的3个实现   只实现了UNPOOLEDDataSource

    1. package com.gmybatis.core;
    2. import javax.sql.DataSource;
    3. import java.io.PrintWriter;
    4. import java.sql.Connection;
    5. import java.sql.DriverManager;
    6. import java.sql.SQLException;
    7. import java.sql.SQLFeatureNotSupportedException;
    8. import java.util.logging.Logger;
    9. /**
    10. * 数据源的实现类--->UNPOOLED
    11. * 不使用数据库连接池
    12. * @author hrui
    13. * @date 2023/9/10 21:33
    14. */
    15. public class UNPOOLEDDataSource implements DataSource {
    16. private String driver;
    17. private String url;
    18. private String username;
    19. private String password;
    20. public UNPOOLEDDataSource(String driver, String url, String username, String password) {
    21. try {
    22. //直接注册驱动
    23. Class.forName("com.mysql.cj.jdbc.Driver");
    24. } catch (ClassNotFoundException e) {
    25. e.printStackTrace();
    26. }
    27. this.driver = driver;
    28. this.url = url;
    29. this.username = username;
    30. this.password = password;
    31. }
    32. @Override
    33. public Connection getConnection() throws SQLException {
    34. //需要driver url username password 定义为属性
    35. Connection connection = DriverManager.getConnection(url, username, password);
    36. return connection;
    37. }
    38. @Override
    39. public Connection getConnection(String username, String password) throws SQLException {
    40. return null;
    41. }
    42. @Override
    43. public T unwrap(Class iface) throws SQLException {
    44. return null;
    45. }
    46. @Override
    47. public boolean isWrapperFor(Class iface) throws SQLException {
    48. return false;
    49. }
    50. @Override
    51. public PrintWriter getLogWriter() throws SQLException {
    52. return null;
    53. }
    54. @Override
    55. public void setLogWriter(PrintWriter out) throws SQLException {
    56. }
    57. @Override
    58. public void setLoginTimeout(int seconds) throws SQLException {
    59. }
    60. @Override
    61. public int getLoginTimeout() throws SQLException {
    62. return 0;
    63. }
    64. @Override
    65. public Logger getParentLogger() throws SQLFeatureNotSupportedException {
    66. return null;
    67. }
    68. }
    1. package com.gmybatis.core;
    2. import javax.sql.DataSource;
    3. import java.io.PrintWriter;
    4. import java.sql.Connection;
    5. import java.sql.SQLException;
    6. import java.sql.SQLFeatureNotSupportedException;
    7. import java.util.logging.Logger;
    8. /**
    9. * 数据源的实现类--->POOLED
    10. * 使用数据库连接池 这里不写连接池
    11. * @author hrui
    12. * @date 2023/9/10 21:32
    13. */
    14. public class POOLEDDataSource implements DataSource {
    15. @Override
    16. public Connection getConnection() throws SQLException {
    17. //从数据库连接池获取Connection对象 这里不写连接池
    18. return null;
    19. }
    20. @Override
    21. public Connection getConnection(String username, String password) throws SQLException {
    22. return null;
    23. }
    24. @Override
    25. public T unwrap(Class iface) throws SQLException {
    26. return null;
    27. }
    28. @Override
    29. public boolean isWrapperFor(Class iface) throws SQLException {
    30. return false;
    31. }
    32. @Override
    33. public PrintWriter getLogWriter() throws SQLException {
    34. return null;
    35. }
    36. @Override
    37. public void setLogWriter(PrintWriter out) throws SQLException {
    38. }
    39. @Override
    40. public void setLoginTimeout(int seconds) throws SQLException {
    41. }
    42. @Override
    43. public int getLoginTimeout() throws SQLException {
    44. return 0;
    45. }
    46. @Override
    47. public Logger getParentLogger() throws SQLFeatureNotSupportedException {
    48. return null;
    49. }
    50. }

    JNDIDataSource

    1. package com.gmybatis.core;
    2. import javax.sql.DataSource;
    3. import java.io.PrintWriter;
    4. import java.sql.Connection;
    5. import java.sql.SQLException;
    6. import java.sql.SQLFeatureNotSupportedException;
    7. import java.util.logging.Logger;
    8. /**
    9. * 数据源的实现类--->JNDI
    10. * 使用第三方的数据库连接池获取Connection对象
    11. * @author hrui
    12. * @date 2023/9/10 21:33
    13. */
    14. public class JNDIDataSource implements DataSource {
    15. @Override
    16. public Connection getConnection() throws SQLException {
    17. return null;
    18. }
    19. @Override
    20. public Connection getConnection(String username, String password) throws SQLException {
    21. return null;
    22. }
    23. @Override
    24. public T unwrap(Class iface) throws SQLException {
    25. return null;
    26. }
    27. @Override
    28. public boolean isWrapperFor(Class iface) throws SQLException {
    29. return false;
    30. }
    31. @Override
    32. public PrintWriter getLogWriter() throws SQLException {
    33. return null;
    34. }
    35. @Override
    36. public void setLogWriter(PrintWriter out) throws SQLException {
    37. }
    38. @Override
    39. public void setLoginTimeout(int seconds) throws SQLException {
    40. }
    41. @Override
    42. public int getLoginTimeout() throws SQLException {
    43. return 0;
    44. }
    45. @Override
    46. public Logger getParentLogger() throws SQLFeatureNotSupportedException {
    47. return null;
    48. }
    49. }

    定义了一个常量类

    1. package com.gmybatis.core;
    2. /**
    3. * 整个框架的常量类
    4. * @author hrui
    5. * @date 2023/9/10 22:26
    6. */
    7. public class Const {
    8. public static final String UN_POOLED_DATASOURCE="UNPOOLED";
    9. public static final String POOLED_DATASOURCE="POOLED";
    10. public static final String JNDI_DATASOURCE="JNDI";
    11. public static final String JDBC_TRANSACTION="JDBC";
    12. public static final String MANAGED_TRANSACTION="MANAGED";
    13. }

    注意测试时候事务管理要选用JDBC   数据源类型要选用UNPOOLED

    mapper路径要写对

    测试基本没问题

    下面把SqlSession加进去

    1. package com.gmybatis.core;
    2. import java.lang.reflect.Method;
    3. import java.sql.Connection;
    4. import java.sql.PreparedStatement;
    5. import java.sql.ResultSet;
    6. import java.sql.SQLException;
    7. import java.util.Locale;
    8. /**
    9. * 专门负责执行SQL语句的会话对象
    10. * @author hrui
    11. * @date 2023/9/10 23:40
    12. */
    13. public class SqlSession {
    14. private SqlSessionFactory sqlSessionFactory;
    15. public SqlSession(SqlSessionFactory sqlSessionFactory) {
    16. this.sqlSessionFactory = sqlSessionFactory;
    17. }
    18. //测试
    19. public static void main(String[] args) {
    20. String sql="insert into t_car values(#{id},#{asd},#{name})";
    21. int fromIndex=0;
    22. int index=1;
    23. while(true) {
    24. int jingIndex = sql.indexOf("#",fromIndex);
    25. if(jingIndex<0){
    26. break;
    27. }
    28. System.out.println(index);
    29. index++;
    30. int youkuohaoIndex = sql.indexOf("}",fromIndex);
    31. String propertyName = sql.substring(jingIndex + 2, youkuohaoIndex).trim();
    32. System.out.println(propertyName);
    33. fromIndex = youkuohaoIndex + 1;
    34. }
    35. }
    36. public int insert(String sqlId,Object obj){
    37. //JDBC代码
    38. Connection connection=null;
    39. PreparedStatement ps=null;
    40. ResultSet rs=null;
    41. int count = 0;
    42. try {
    43. connection=sqlSessionFactory.getTransaction().getConnection();
    44. String sql=sqlSessionFactory.getMappedStatementMap().get(sqlId).getSql();
    45. String sql1 = sql.replaceAll("#\\{[0-9A-Za-z_$]*}", "?");//使用正则替换
    46. ps = connection.prepareStatement(sql1);
    47. //有几个?号 不知道将pojo对象中的哪个属性给哪个 暂时全当String
    48. int fromIndex=0;
    49. int index=1;
    50. while(true) {
    51. int jingIndex = sql.indexOf("#",fromIndex);
    52. if(jingIndex<0){
    53. break;
    54. }
    55. //System.out.println(index);
    56. int youkuohaoIndex = sql.indexOf("}",fromIndex);
    57. String propertyName = sql.substring(jingIndex + 2, youkuohaoIndex).trim();
    58. //System.out.println(propertyName);
    59. fromIndex = youkuohaoIndex + 1;
    60. String getMethodName="get"+propertyName.toUpperCase().charAt(0)+propertyName.substring(1);
    61. Method getMethod=obj.getClass().getDeclaredMethod(getMethodName);
    62. Object invoke = getMethod.invoke(obj);
    63. ps.setString(index,invoke.toString());
    64. index++;
    65. }
    66. count = ps.executeUpdate();
    67. } catch (Exception e) {
    68. e.printStackTrace();
    69. }
    70. //这里不要加 不然直接关闭了
    71. // finally {
    72. // if(rs!=null){
    73. // try {
    74. // rs.close();
    75. // } catch (SQLException e) {
    76. // e.printStackTrace();
    77. // }
    78. // }
    79. // if(ps!=null){
    80. // try {
    81. // ps.close();
    82. // } catch (SQLException e) {
    83. // e.printStackTrace();
    84. // }
    85. // }
    86. // if(connection!=null){
    87. // try {
    88. // connection.close();
    89. // } catch (SQLException e) {
    90. // e.printStackTrace();
    91. // }
    92. // }
    93. // }
    94. return count;
    95. }
    96. public Object selectOne(){
    97. return null;
    98. }
    99. public void commit(){
    100. sqlSessionFactory.getTransaction().commit();
    101. }
    102. public void rollback(){
    103. sqlSessionFactory.getTransaction().rollback();
    104. }
    105. public void close(){
    106. sqlSessionFactory.getTransaction().close();
    107. }
    108. }

    修改sqlSessionFactory

    1. package com.gmybatis.core;
    2. import java.util.Map;
    3. /**
    4. *SqlSessionFactory对象,一个数据库对应一个SqlSessionFactory对象
    5. * 通过SqlSessionFactory对象可以获得SqlSession对象(开启会话)
    6. * 一个SqlSessionFactory对象可以开启多个SqlSession会话
    7. * @author hrui
    8. * @date 2023/9/10 20:34
    9. */
    10. public class SqlSessionFactory {
    11. //事务管理器 可以是JDBC:原生JDBC事务 也可以是MANAGED:交容器管理,比如Spring 可以灵活切换建议定义为接口
    12. private Transaction transaction;
    13. //数据源属性 因为已经在事务管理器里定义了数据源,因此这里不需要定义 可以通过事务管理器来获取
    14. private Map<String,MappedStatement> mappedStatementMap;
    15. public SqlSessionFactory() {
    16. }
    17. public SqlSessionFactory(Transaction transaction, Map<String, MappedStatement> mappedStatementMap) {
    18. this.transaction = transaction;
    19. this.mappedStatementMap = mappedStatementMap;
    20. }
    21. public Transaction getTransaction() {
    22. return transaction;
    23. }
    24. public void setTransaction(Transaction transaction) {
    25. this.transaction = transaction;
    26. }
    27. public Map<String, MappedStatement> getMappedStatementMap() {
    28. return mappedStatementMap;
    29. }
    30. public void setMappedStatementMap(Map<String, MappedStatement> mappedStatementMap) {
    31. this.mappedStatementMap = mappedStatementMap;
    32. }
    33. /**
    34. * 获取sql会话对象
    35. * @param flag
    36. * @return
    37. */
    38. public SqlSession openSession(){
    39. //开启会话的前提是开启连接
    40. transaction.openConnection();
    41. //创建SqlSession对象
    42. SqlSession sqlSession=new SqlSession(this);
    43. return sqlSession;
    44. }
    45. }

    JDBCTransaction的openConnection的代码加上开启事务

    1. package com.gmybatis.core;
    2. import javax.sql.DataSource;
    3. import java.sql.Connection;
    4. import java.sql.SQLException;
    5. /**
    6. * JDBC事务管理器
    7. * @author hrui
    8. * @date 2023/9/10 21:19
    9. */
    10. public class JDBCTransaction implements Transaction{
    11. //数据源属性
    12. private DataSource dataSource;
    13. /**
    14. * 自动提交标志
    15. * true为自动提交
    16. * false为不自动提交
    17. */
    18. private boolean aotoCommit;
    19. private Connection connection;
    20. /**
    21. * 用于外界获取Connection
    22. * 外界用的Connection对象 必须和事务管理器的是同一个
    23. * 这样才可以在事务管理器里 commit rollback closed
    24. * @return
    25. */
    26. @Override
    27. public Connection getConnection() {
    28. return connection;
    29. }
    30. //用于给属性connection赋值 只要事务管理器不换 连接就是同一个连接、
    31. @Override
    32. public void openConnection(){
    33. if(connection==null){
    34. try {
    35. connection=dataSource.getConnection();
    36. //开启事务
    37. connection.setAutoCommit(aotoCommit);
    38. } catch (SQLException e) {
    39. e.printStackTrace();
    40. }
    41. }
    42. }
    43. public JDBCTransaction(DataSource dataSource, Boolean aotoCommit) {
    44. this.dataSource = dataSource;
    45. this.aotoCommit = aotoCommit;
    46. }
    47. @Override
    48. public void commit() {
    49. //控制事务的时候需要调用JDBC里的连接对象 需要数据源
    50. try {
    51. connection.commit();
    52. } catch (SQLException e) {
    53. e.printStackTrace();
    54. }
    55. }
    56. @Override
    57. public void rollback() {
    58. try {
    59. connection.rollback();
    60. } catch (SQLException e) {
    61. e.printStackTrace();
    62. }
    63. }
    64. @Override
    65. public void close() {
    66. try {
    67. connection.commit();
    68. } catch (SQLException e) {
    69. e.printStackTrace();
    70. }
    71. }
    72. }

    引入mysql依赖测试  新建表

    新建实体类

    1. package com.gmybatis.core;
    2. /**
    3. * @author hrui
    4. * @date 2023/9/11 0:31
    5. */
    6. public class Car {
    7. private String id;
    8. private String name;
    9. private String age;
    10. public Car() {
    11. }
    12. public Car(String id, String name, String age) {
    13. this.id = id;
    14. this.name = name;
    15. this.age = age;
    16. }
    17. public String getId() {
    18. return id;
    19. }
    20. public void setId(String id) {
    21. this.id = id;
    22. }
    23. public String getName() {
    24. return name;
    25. }
    26. public void setName(String name) {
    27. this.name = name;
    28. }
    29. public String getAge() {
    30. return age;
    31. }
    32. public void setAge(String age) {
    33. this.age = age;
    34. }
    35. }

    映射文件

  • 相关阅读:
    ubuntu安装nvm
    C++ 运算符
    java中的instanceof 的用法
    Python windows安装3.10.0版本
    ES8(Java API Client)查询详解
    深入探索Spring Boot的自动配置机制
    typora使用PicGo自动上传图片到chevereto图床
    SSM - Springboot - MyBatis-Plus 全栈体系(八)
    AI绘画,我们究竟该支持还是反对?
    Windows10找不到msvcr100.dll如何修复呢?详细有效的修复方法分享
  • 原文地址:https://blog.csdn.net/tiantiantbtb/article/details/132793874