手写Mybatis

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

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

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

新建模块演示dom4j解析.xml

目录放错了  无所谓

引入依赖

从原来项目可以拷贝过来

就些简单配置就好

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

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.junit.Test;import java.io.InputStream;
import java.util.List;/*** @author hrui* @date 2023/9/10 18:24*/
public class ParseXMLByDom4JTest {//解析Mapper映射文件@Testpublic void testParseSqlMapperXML() throws DocumentException {//创建SAXReader对象SAXReader reader=new SAXReader();//获取输入流(将resources目录下的mybatis-config1.xml转输入流)InputStream inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream("mapper/CarMapperABC.xml");//读XML文件Document document=reader.read(inputStream);String xpath="/mapper";Element mapper =(Element) document.selectSingleNode(xpath);String namespace = mapper.attributeValue("namespace");System.out.println(namespace);//aaa//获取mapper节点下所有子节点List<Element> elements = mapper.elements();elements.forEach(e->{//获取sqlIdString id = e.attributeValue("id");//获取resultType  没有返回nullSystem.out.println(id);//获取标签中的sql语句,取出前后空白String sql = e.getTextTrim();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})//现在是:insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})//内部肯定使用JDBC:insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,?,?,?,?,?)//转换String newSql = sql.replaceAll("#\\{[0-9A-Za-z_$]*}", "?");//使用正则替换System.out.println(newSql);//insert into t_car(id,car_num,brand,guide_price,produce_time,car_type) values(null,?,?,?,?,?)});}//解析核心配置文件@Testpublic void testParseMybatisConfigXML() throws DocumentException {//创建SAXReader对象SAXReader reader=new SAXReader();//获取输入流(将resources目录下的mybatis-config1.xml转输入流)InputStream inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream("mybatis-config1.xml");//读XML文件Document document=reader.read(inputStream);//System.out.println(document);//获取根标签Element root = document.getRootElement();//System.out.println(root.getName());//configuration//获取跟标签后肯定是去获取环境 environments 获取里面的default数据库id//获取默认的环境id//xpath是做标签路径匹配的.能够让我们快速定位XML文件中的元素//以下的xpath:从跟下开始找configuration,然后找configuration标签下的子标签environmentsString xpath="/configuration/environments";Element element = (Element)document.selectSingleNode(xpath);//System.out.println(element);//获取属性的值 默认环境idString aDefaultEnvivironmentId = element.attributeValue("default");//System.out.println("默认环境id是:"+aDefaultEnvivironmentId);//development//去找environment的 id属性,然后和默认环境id比较,确定默认使用哪个数据库//下面是xpath的写法 意思找xpath="/configuration/environments/environment[@id='"+aDefaultEnvivironmentId+"']";Element enviroment =(Element) document.selectSingleNode(xpath);//System.out.println(enviroment.getName());environment//获取environment节点下的transactionManagerElement transactionManager = enviroment.element("transactionManager");String transactionType = transactionManager.attributeValue("type");//System.out.println("事务管理器的类型:"+transactionType);//获取事务管理器类型----->JDBC//接着获取datasource节点Element datasource = enviroment.element("dataSource");String dataSourcetype = datasource.attributeValue("type");System.out.println("数据源的类型:"+dataSourcetype);//POOLED//获取dataSource下的所有子节点List<Element> propertyElements = datasource.elements();//遍历propertyElements.forEach(e->{String name = e.attributeValue("name");String value = e.attributeValue("value");System.out.println("name="+name+",value="+value);});//获取所有的mapper标签//如果你不想从跟下开始获取,而是想从任意位置开始,获取某个标签,xpath可以这样写xpath="//mapper";//  两个//开始List<Node> mappers = document.selectNodes(xpath);//遍历mappers.forEach(n->{Element e=(Element)n;String resource = e.attributeValue("resource");System.out.println(resource);});}
}

新建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

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

2.SqlSessionFactoryBuilder   构建器对象

package com.gmybatis.core;import com.gmybatis.utils.Resources;
import jdk.nashorn.internal.ir.ReturnNode;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;import javax.sql.DataSource;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** SqlSessionFactory的构建器对象* 通过SqlSessionFactoryBuilder的build方法来解析核心配置文件,* 然后创建SqlSessionFactory对象* @author hrui* @date 2023/9/10 20:31*/
public class SqlSessionFactoryBuilder {public SqlSessionFactoryBuilder() {}/*** 解析核心配置文件,来构建SqlSessionFactory* @param in* @return*/public SqlSessionFactory build(InputStream in){SqlSessionFactory sqlSessionFactory=null;try {//解析核心配置文件//创建SAXReader对象SAXReader reader=new SAXReader();//读XML文件Document document=reader.read(in);//获取environmentsElement environments =(Element) document.selectSingleNode("/configuration/environments");//获取default属性值String defaultId = environments.attributeValue("default");//拿匹配的环境节点Element environment = (Element)document.selectSingleNode("/configuration/environments/environment[@id='"+defaultId+"']");//获取transactionManagerElement transactionManagerEle = environment.element("transactionManager");//获取dataSourceElement dataSourceEle = environment.element("dataSource");//获取mapperList<Node> mapperList = document.selectNodes("//mapper");//获取整个配置文件中所有的mapper标签//用于封装所有mappers里面的mapper的路径List<String> sqlMapperXMLPathList=new ArrayList<>();mapperList.forEach(n->{Element e=(Element) n;String resource = e.attributeValue("resource");sqlMapperXMLPathList.add(resource);});//获取数据源对象DataSource dataSource=getDataSource(dataSourceEle);//定义事务管理器Transaction transaction=getTransaction(transactionManagerEle,dataSource);//key是namespase+sql的idMap<String,MappedStatement> MappedStatements=getMappedStatements(sqlMapperXMLPathList);//解析完成之后,构建出SqlSessionFactory对象sqlSessionFactory=new SqlSessionFactory(transaction,MappedStatements);} catch (Exception e) {e.printStackTrace();}return sqlSessionFactory;}private Map<String, MappedStatement> getMappedStatements(List<String> sqlMapperXMLPathList) {Map<String,MappedStatement> map=new HashMap<>();sqlMapperXMLPathList.forEach(path->{try {//创建SAXReader对象SAXReader reader=new SAXReader();//读XXXMapper.XML映射文件Document document=reader.read(Resources.getResourceAsStream(path));//解析映射文件Element mapper = (Element)document.selectSingleNode("mapper");//带不带/都可以String namespace = mapper.attributeValue("namespace");List<Element> elements = mapper.elements();elements.forEach(e->{String id = e.attributeValue("id");//namespase+idString sqlId=namespace+"."+id;String resultType = e.attributeValue("resultType");String sqlContent = e.getTextTrim();MappedStatement mappedStatement=new MappedStatement(sqlContent,resultType);map.put(sqlId,mappedStatement);});} catch (DocumentException e) {e.printStackTrace();}});return map;}private DataSource getDataSource(Element dataSourceEle) {Map<String,String> map=new HashMap<>();//获取节点下所有propertyList<Element> propertys = dataSourceEle.elements("property");propertys.forEach(e->{String name = e.attributeValue("name");String value = e.attributeValue("value");map.put(name,value);});DataSource dataSource=null;//type 可能是  POOLED UNPOOLED JNDIString type = dataSourceEle.attributeValue("type");
//        if(type.equalsIgnoreCase("POOLED")){  //这里简易定义常量类
//
//        }if(type.equalsIgnoreCase(Const.POOLED_DATASOURCE)){dataSource=new POOLEDDataSource();}if(type.equalsIgnoreCase(Const.UN_POOLED_DATASOURCE)){//只对这个做了实现dataSource=new UNPOOLEDDataSource(map.get("driver"),map.get("url"),map.get("username"),map.get("password"));}if(type.equalsIgnoreCase(Const.JNDI_DATASOURCE)){dataSource=new JNDIDataSource();}return dataSource;}private Transaction getTransaction(Element transactionManager, DataSource dataSource) {Transaction transaction=null;String type = transactionManager.attributeValue("type");if(type.equalsIgnoreCase(Const.JDBC_TRANSACTION)){transaction=new JDBCTransaction(dataSource,false );//只对JDBCTransaction做了实现}if(type.equalsIgnoreCase(Const.MANAGED_TRANSACTION)){transaction=new MANAGEDTransaction();}return transaction;}}

3.SqlSessionFactory

package com.gmybatis.core;import java.util.Map;/***SqlSessionFactory对象,一个数据库对应一个SqlSessionFactory对象* 通过SqlSessionFactory对象可以获得SqlSession对象(开启会话)* 一个SqlSessionFactory对象可以开启多个SqlSession会话* @author hrui* @date 2023/9/10 20:34*/
public class SqlSessionFactory {//事务管理器 可以是JDBC:原生JDBC事务 也可以是MANAGED:交容器管理,比如Spring   可以灵活切换建议定义为接口private Transaction transaction;//数据源属性 因为已经在事务管理器里定义了数据源,因此这里不需要定义  可以通过事务管理器来获取private Map<String,MappedStatement> mappedStatementMap;public SqlSessionFactory() {}public SqlSessionFactory(Transaction transaction, Map<String, MappedStatement> mappedStatementMap) {this.transaction = transaction;this.mappedStatementMap = mappedStatementMap;}public Transaction getTransaction() {return transaction;}public void setTransaction(Transaction transaction) {this.transaction = transaction;}public Map<String, MappedStatement> getMappedStatementMap() {return mappedStatementMap;}public void setMappedStatementMap(Map<String, MappedStatement> mappedStatementMap) {this.mappedStatementMap = mappedStatementMap;}//    public SqlSession openSession(boolean flag){
//        return null;
//    }
}

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

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

JDBCTransaction

package com.gmybatis.core;import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;/*** JDBC事务管理器* @author hrui* @date 2023/9/10 21:19*/
public class JDBCTransaction implements Transaction{//数据源属性private  DataSource dataSource;/*** 自动提交标志* true为自动提交* false为不自动提交*/private Boolean aotoCommit;private Connection connection;/*** 用于外界获取Connection* 外界用的Connection对象 必须和事务管理器的是同一个* 这样才可以在事务管理器里  commit  rollback  closed* @return*/@Overridepublic Connection getConnection() {return connection;}//用于给属性connection赋值 只要事务管理器不换 连接就是同一个连接、@Overridepublic void openConnection(){if(connection==null){try {connection=dataSource.getConnection();} catch (SQLException e) {e.printStackTrace();}}}public JDBCTransaction(DataSource dataSource, Boolean aotoCommit) {this.dataSource = dataSource;this.aotoCommit = aotoCommit;}@Overridepublic void commit() {//控制事务的时候需要调用JDBC里的连接对象 需要数据源try {connection.commit();} catch (SQLException e) {e.printStackTrace();}}@Overridepublic void rollback() {try {connection.rollback();} catch (SQLException e) {e.printStackTrace();}}@Overridepublic void close() {try {connection.commit();} catch (SQLException e) {e.printStackTrace();}}
}

MANAGEDTransaction

package com.gmybatis.core;import java.sql.Connection;/*** MANAGED事务管理器* @author hrui* @date 2023/9/10 21:19*/
public class MANAGEDTransaction implements Transaction{@Overridepublic void commit() {}@Overridepublic void rollback() {}@Overridepublic void close() {}@Overridepublic void openConnection() {}@Overridepublic Connection getConnection() {return null;}
}

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

package com.gmybatis.core;import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;/*** 数据源的实现类--->UNPOOLED* 不使用数据库连接池* @author hrui* @date 2023/9/10 21:33*/
public class UNPOOLEDDataSource implements DataSource {private String driver;private String url;private String username;private String password;public UNPOOLEDDataSource(String driver, String url, String username, String password) {try {//直接注册驱动Class.forName("com.mysql.cj.jdbc.Driver");} catch (ClassNotFoundException e) {e.printStackTrace();}this.driver = driver;this.url = url;this.username = username;this.password = password;}@Overridepublic Connection getConnection() throws SQLException {//需要driver url username password 定义为属性Connection connection = DriverManager.getConnection(url, username, password);return connection;}@Overridepublic Connection getConnection(String username, String password) throws SQLException {return null;}@Overridepublic <T> T unwrap(Class<T> iface) throws SQLException {return null;}@Overridepublic boolean isWrapperFor(Class<?> iface) throws SQLException {return false;}@Overridepublic PrintWriter getLogWriter() throws SQLException {return null;}@Overridepublic void setLogWriter(PrintWriter out) throws SQLException {}@Overridepublic void setLoginTimeout(int seconds) throws SQLException {}@Overridepublic int getLoginTimeout() throws SQLException {return 0;}@Overridepublic Logger getParentLogger() throws SQLFeatureNotSupportedException {return null;}
}
package com.gmybatis.core;import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;/*** 数据源的实现类--->POOLED* 使用数据库连接池  这里不写连接池* @author hrui* @date 2023/9/10 21:32*/
public class POOLEDDataSource implements DataSource {@Overridepublic Connection getConnection() throws SQLException {//从数据库连接池获取Connection对象 这里不写连接池return null;}@Overridepublic Connection getConnection(String username, String password) throws SQLException {return null;}@Overridepublic <T> T unwrap(Class<T> iface) throws SQLException {return null;}@Overridepublic boolean isWrapperFor(Class<?> iface) throws SQLException {return false;}@Overridepublic PrintWriter getLogWriter() throws SQLException {return null;}@Overridepublic void setLogWriter(PrintWriter out) throws SQLException {}@Overridepublic void setLoginTimeout(int seconds) throws SQLException {}@Overridepublic int getLoginTimeout() throws SQLException {return 0;}@Overridepublic Logger getParentLogger() throws SQLFeatureNotSupportedException {return null;}
}

JNDIDataSource

package com.gmybatis.core;import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;/*** 数据源的实现类--->JNDI* 使用第三方的数据库连接池获取Connection对象* @author hrui* @date 2023/9/10 21:33*/
public class JNDIDataSource implements DataSource {@Overridepublic Connection getConnection() throws SQLException {return null;}@Overridepublic Connection getConnection(String username, String password) throws SQLException {return null;}@Overridepublic <T> T unwrap(Class<T> iface) throws SQLException {return null;}@Overridepublic boolean isWrapperFor(Class<?> iface) throws SQLException {return false;}@Overridepublic PrintWriter getLogWriter() throws SQLException {return null;}@Overridepublic void setLogWriter(PrintWriter out) throws SQLException {}@Overridepublic void setLoginTimeout(int seconds) throws SQLException {}@Overridepublic int getLoginTimeout() throws SQLException {return 0;}@Overridepublic Logger getParentLogger() throws SQLFeatureNotSupportedException {return null;}
}

定义了一个常量类

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

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

mapper路径要写对

测试基本没问题

下面把SqlSession加进去

package com.gmybatis.core;import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Locale;/*** 专门负责执行SQL语句的会话对象* @author hrui* @date 2023/9/10 23:40*/
public class SqlSession {private SqlSessionFactory sqlSessionFactory;public SqlSession(SqlSessionFactory sqlSessionFactory) {this.sqlSessionFactory = sqlSessionFactory;}//测试public static void main(String[] args) {String sql="insert into t_car values(#{id},#{asd},#{name})";int fromIndex=0;int index=1;while(true) {int jingIndex = sql.indexOf("#",fromIndex);if(jingIndex<0){break;}System.out.println(index);index++;int youkuohaoIndex = sql.indexOf("}",fromIndex);String propertyName = sql.substring(jingIndex + 2, youkuohaoIndex).trim();System.out.println(propertyName);fromIndex = youkuohaoIndex + 1;}}public int insert(String sqlId,Object obj){//JDBC代码Connection connection=null;PreparedStatement ps=null;ResultSet rs=null;int count = 0;try {connection=sqlSessionFactory.getTransaction().getConnection();String sql=sqlSessionFactory.getMappedStatementMap().get(sqlId).getSql();String sql1 = sql.replaceAll("#\\{[0-9A-Za-z_$]*}", "?");//使用正则替换ps = connection.prepareStatement(sql1);//有几个?号 不知道将pojo对象中的哪个属性给哪个 暂时全当Stringint fromIndex=0;int index=1;while(true) {int jingIndex = sql.indexOf("#",fromIndex);if(jingIndex<0){break;}//System.out.println(index);int youkuohaoIndex = sql.indexOf("}",fromIndex);String propertyName = sql.substring(jingIndex + 2, youkuohaoIndex).trim();//System.out.println(propertyName);fromIndex = youkuohaoIndex + 1;String getMethodName="get"+propertyName.toUpperCase().charAt(0)+propertyName.substring(1);Method getMethod=obj.getClass().getDeclaredMethod(getMethodName);Object invoke = getMethod.invoke(obj);ps.setString(index,invoke.toString());index++;}count = ps.executeUpdate();} catch (Exception e) {e.printStackTrace();}//这里不要加 不然直接关闭了
//        finally {
//            if(rs!=null){
//                try {
//                    rs.close();
//                } catch (SQLException e) {
//                    e.printStackTrace();
//                }
//            }
//            if(ps!=null){
//                try {
//                    ps.close();
//                } catch (SQLException e) {
//                    e.printStackTrace();
//                }
//            }
//            if(connection!=null){
//                try {
//                    connection.close();
//                } catch (SQLException e) {
//                    e.printStackTrace();
//                }
//            }
//        }return count;}public Object selectOne(){return null;}public void commit(){sqlSessionFactory.getTransaction().commit();}public void rollback(){sqlSessionFactory.getTransaction().rollback();}public void close(){sqlSessionFactory.getTransaction().close();}
}

修改sqlSessionFactory

package com.gmybatis.core;import java.util.Map;/***SqlSessionFactory对象,一个数据库对应一个SqlSessionFactory对象* 通过SqlSessionFactory对象可以获得SqlSession对象(开启会话)* 一个SqlSessionFactory对象可以开启多个SqlSession会话* @author hrui* @date 2023/9/10 20:34*/
public class SqlSessionFactory {//事务管理器 可以是JDBC:原生JDBC事务 也可以是MANAGED:交容器管理,比如Spring   可以灵活切换建议定义为接口private Transaction transaction;//数据源属性 因为已经在事务管理器里定义了数据源,因此这里不需要定义  可以通过事务管理器来获取private Map<String,MappedStatement> mappedStatementMap;public SqlSessionFactory() {}public SqlSessionFactory(Transaction transaction, Map<String, MappedStatement> mappedStatementMap) {this.transaction = transaction;this.mappedStatementMap = mappedStatementMap;}public Transaction getTransaction() {return transaction;}public void setTransaction(Transaction transaction) {this.transaction = transaction;}public Map<String, MappedStatement> getMappedStatementMap() {return mappedStatementMap;}public void setMappedStatementMap(Map<String, MappedStatement> mappedStatementMap) {this.mappedStatementMap = mappedStatementMap;}/*** 获取sql会话对象* @param flag* @return*/public SqlSession openSession(){//开启会话的前提是开启连接transaction.openConnection();//创建SqlSession对象SqlSession sqlSession=new SqlSession(this);return sqlSession;}
}

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

package com.gmybatis.core;import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;/*** JDBC事务管理器* @author hrui* @date 2023/9/10 21:19*/
public class JDBCTransaction implements Transaction{//数据源属性private  DataSource dataSource;/*** 自动提交标志* true为自动提交* false为不自动提交*/private boolean aotoCommit;private Connection connection;/*** 用于外界获取Connection* 外界用的Connection对象 必须和事务管理器的是同一个* 这样才可以在事务管理器里  commit  rollback  closed* @return*/@Overridepublic Connection getConnection() {return connection;}//用于给属性connection赋值 只要事务管理器不换 连接就是同一个连接、@Overridepublic void openConnection(){if(connection==null){try {connection=dataSource.getConnection();//开启事务connection.setAutoCommit(aotoCommit);} catch (SQLException e) {e.printStackTrace();}}}public JDBCTransaction(DataSource dataSource, Boolean aotoCommit) {this.dataSource = dataSource;this.aotoCommit = aotoCommit;}@Overridepublic void commit() {//控制事务的时候需要调用JDBC里的连接对象 需要数据源try {connection.commit();} catch (SQLException e) {e.printStackTrace();}}@Overridepublic void rollback() {try {connection.rollback();} catch (SQLException e) {e.printStackTrace();}}@Overridepublic void close() {try {connection.commit();} catch (SQLException e) {e.printStackTrace();}}
}

引入mysql依赖测试  新建表

新建实体类

package com.gmybatis.core;/*** @author hrui* @date 2023/9/11 0:31*/
public class Car {private String id;private String name;private String age;public Car() {}public Car(String id, String name, String age) {this.id = id;this.name = name;this.age = age;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAge() {return age;}public void setAge(String age) {this.age = age;}
}

映射文件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/129096.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue学习之属性绑定

内容渲染 采用 &#xff1a;进行属性渲染创建 demo3.html,内容如下 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"&…

CHS零壹视频恢复程序OCR使用方法

目前CHS零壹视频恢复程序监控版、专业版、高级版已经支持了OCR&#xff0c;OCR是一种光学识别系统&#xff0c;通俗说就和扫描仪带的OCR软件一样的原理&#xff1a; 分析照片->OCR获取字符串->整理字符串->输出 使用方法如下&#xff08;以CHS零壹视频恢复程序监控版…

使用LlamaIndex构建自己的PandasAI

推荐&#xff1a;使用 NSDT场景编辑器 快速搭建3D应用场景 Pandas AI 是一个 Python 库&#xff0c;它利用生成 AI 的强大功能来增强流行的数据分析库 Pandas。只需一个简单的提示&#xff0c;Pandas AI 就可以让你执行复杂的数据清理、分析和可视化&#xff0c;而这以前需要很…

STL线程各种容器对比、数组和vector如何互相转换

STL vector如何扩展内存和释放内存STL中各种容器对比STL中的swap函数STL中哈希表扩容STL迭代器失效的情况和原因vector删除元素后如何避免当前迭代器会失效vector的iterator和const_iterator和const iterator vector如何扩展内存和释放内存 内存增长 1.5还是2倍扩容 gcc 二倍扩…

微信小程序ibeacon搜索功能制作

以下是一个完整的微信小程序代码示例&#xff0c;演示如何实现iBeacon搜索功能&#xff1a; // 在小程序页面中的js文件中编写代码Page({data: {beacons: [] // 存储搜索到的iBeacon设备信息},onReady() {// 初始化iBeaconwx.startBeaconDiscovery({uuids: [你的UUID], // 替换…

数据结构和算法(1):开始

算法概述 所谓算法&#xff0c;即特定计算模型下&#xff0c;旨在解决特定问题的指令序列 输入 待处理的信息&#xff08;问题&#xff09; 输出 经处理的信息&#xff08;答案&#xff09; 正确性 的确可以解决指定的问题 确定性 任一算法都可以描述为一个由基本操作组成的序…

用户促活留存新方式——在APP中嵌入小游戏

随着APP同类产品的不断出现&#xff0c;APP开发者们面临着激烈的竞争&#xff0c;很多APP下载后被新的APP取代&#xff0c;获客成本越来越高。同时开发者还会面临用户粘性差、忠诚度低、用完即走、留存困难&#xff0c;商业化价值被大大缩减。 在APP中植入小游戏来提高用户活跃…

Vue——vue3+element plus实现多选表格使用ajax发送id数组

代码来源: Vue 3结合element plus&#xff08;问题总结二&#xff09;之 table组件实现多选和清除选中&#xff08;在vue3中获取ref 的Dom&#xff09;_multipletableref.value.togglerowselection()打印出来的是u_子时不睡的博客-CSDN博客 前言 为了实现批量删除功能的功能…

【Python爬虫实战】爬虫封你ip就不会了?ip代理池安排上

前言 在进行网络爬取时&#xff0c;使用代理是经常遇到的问题。由于某些网站的限制&#xff0c;我们可能会被封禁或者频繁访问时会遇到访问速度变慢等问题。因此&#xff0c;我们需要使用代理池来避免这些问题。本文将为大家介绍如何使用IP代理池进行爬虫&#xff0c;并带有代…

C语言练习:输入日期输出该日期为当年第几天

用scanf()输入某年某月某日&#xff0c;判断这一天是这一年的第几天。以3月5日为例&#xff0c;应该先把前两个月的加起来&#xff0c;然后再加上5天即本年的第几天&#xff0c;特殊情况&#xff0c;闰年且输入月份≥3时需考虑多加一天。注&#xff1a;判断年份是否为闰年的方法…

【C刷题】day1

一、选择题 1.正确的输出结果是 int x5,y7; void swap() { int z; zx; xy; yz; } int main() { int x3,y8; swap(); printf("%d,%d\n"&#xff0c;x, y); return 0; } 【答案】&#xff1a; 3&#xff0c;8 【解析】&#xff1a; 考点&#xff1a; &#xff…

Matlab如何导入Excel数据并进行FFT变换

如果你发现某段信号里面有干扰&#xff0c;想要分析这段信号里面的频率成分&#xff0c;就可以使用matlab导入Excel数据后进行快速傅里叶变换&#xff08;fft&#xff09;。 先直接上使用方法&#xff0c;后面再补充理论知识。 可以通过串口将需要分析的数据发送到串口助手&a…

postgresql-窗口函数

postgresql-窗口函数 窗口函数简介窗口函数的定义分区排序选项窗口选项 窗口函数简介 包括 AVG、COUNT、MAX、MIN、SUM 以及 STRING_AGG。聚合函数的作用是针对一组数据行进行运算&#xff0c;并且返回一条汇总结果 分析的窗口函数&#xff08;Window Function&#xff09;。 …

投稿指南【NO.12_8】【极易投中】核心期刊投稿(组合机床与自动化加工技术)

近期有不少同学咨询投稿期刊的问题&#xff0c;大部分院校的研究生都有发学术论文的要求&#xff0c;少部分要求高的甚至需要SCI或者多篇核心期刊论文才可以毕业&#xff0c;但是核心期刊要求论文质量高且审稿周期长&#xff0c;所以本博客梳理一些计算机特别是人工智能相关的期…

单相并联下垂控原理

Part1 上述有个核心的piont是等效阻抗上的电压一般时很小的&#xff0c;这就导致逆变器输出电压矢量E和负载电压矢量UL之间的夹角很小 》基于上述的结论有助于我们去简化下垂控制的公式&#xff01;&#xff01;&#xff01; Part2 上述得到负载电流&#xff0c;接着乘以负载…

mac 查看端口占用

sudo lsof -i tcp:port # 示例 sudo lsof -i tcp:8080 杀死进程 sudo kill -9 PID # 示例 sudo kill -9 8080

基于奇偶模的跨线桥(crossover)分析

文章目录 1、ADS建模2、奇偶模分析2.1 Port1→Port2传输特性2.1.1奇模分析2.1.2偶模分析 2.2 Port1→Port4传输特性 附&#xff1a;正交混合网络的奇偶模分析1、 Port1→Port21.1奇模分析1.2Port1→Port2偶模分析1.3 奇模传输与偶模传输相位关系![在这里插入图片描述](https://…

蚂蚁开源编程大模型,提高开发效率

据悉&#xff0c;日前蚂蚁集团首次开源了代码大模型 CodeFuse&#xff0c;而这是蚂蚁自研的代码生成专属大模型&#xff0c;可以根据开发者的输入提供智能建议和实时支持&#xff0c;帮助开发者自动生成代码、自动增加注释、自动生成测试用例、修复和优化代码等kslouitusrtdf。…

rrweb入门

rrweb 背景 rrweb 是 record and replay the web&#xff0c;是当下很流行的一个录制屏幕的开源库。与我们传统认知的录屏方式&#xff08;如 WebRTC&#xff09;不同的是&#xff0c;rrweb 录制的不是真正的视频流&#xff0c;而是一个记录页面 DOM 变化的 JSON 数组&#x…

zookeeper没有.log日志,只有.out日志

zookeeper没有.log日志&#xff0c;只有.out日志 背景&#xff1a;发现zookeeper没有.log日志&#xff0c;只有.out日志 发现在logs目录下&#xff0c;只有.out文件&#xff0c;且每次重启zk&#xff0c;.out日志都会被覆盖写 为了有完整的log日志&#xff0c;需要如下参数 1…