(四)手写简单版MyBatis框架

news2024/11/15 2:11:52

文章目录

  • 环境搭建
  • 第一步:资源⼯具类
  • 第二步:定义SqlSessionFactoryBuilder类
  • 第三步:定义SqlSessionFactory类
  • 第四步:定义JDBC事务管理器
  • 第五步:定义数据源类
  • 第六步:定义MyMappedStatement类
  • 第七步:完善SqlSessionFactory类
  • 第八步:完善SqlSessionFactoryBuilder中的build⽅法
  • 第九步:添加openSession⽅法获取会话对象
  • 第十步:创建会话类MySqlSession
  • 测试

环境搭建

首先我们用mybatis的时候有很多XML文件,有核心配置文件和映射文件等等,我们需要解析这些XML文件,可以使用dom4j解析XML⽂件

IDEA中创建Maven模块:我的模块名叫My_mybatis
请添加图片描述

dom4j可以参考:https://blog.csdn.net/weixin_45832694/article/details/127536145?spm=1001.2014.3001.5502
引入dom4j依赖和mysql驱动依赖,为了测试方便还需要引入junit依赖

    <!--dem4j依赖-->
    <dependency>
      <groupId>org.dom4j</groupId>
      <artifactId>dom4j</artifactId>
      <version>2.1.3</version>
    </dependency>
    <!--jaxen依赖-->
    <dependency>
      <groupId>jaxen</groupId>
      <artifactId>jaxen</artifactId>
      <version>1.2.0</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.2</version>
      <scope>test</scope>
    </dependency>
    <!--mysql依赖-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.30</version>
    </dependency>

⼿写框架之前,我们不知道从哪入手,可以参考之前的mybatis程序

public class MybatisIntroductionTest {
    public static void main(String[] args) throws IOException {
        // 获取SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

        // 获取SqlSessionFactory对象
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml"); // Resources.getResourceAsStream默认就是从类的根路径下开始查找资源。
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is); // 一般情况下都是一个数据库对应一个SqlSessionFactory对象。

        // 获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession(); // 如果使用的事务管理器是JDBC的话,底层实际上会执行:conn.setAutoCommit(false);

        // 执行SQL语句,这里insert里的值是XXXMapper.xml
        int count = sqlSession.insert("insertCar"); // 返回值是影响数据库表当中的记录条数。

        System.out.println("插入了几条记录:" + count);

        // 手动提交
        sqlSession.commit(); // 如果使用的事务管理器是JDBC的话,底层实际上还是会执行conn.commit();

    }
}

第一步:资源⼯具类

可以看出Resources.getResourceAsStream,Resources是一个工具类,调用静态方法getResourceAsStream,自定义一个工具类MyResouces

/**
 * 提供一个工具类,完成类路径的加载
 */
public class MyResouces {
    private MyResouces(){//工具类构造方法私有化
    }

    /**
     * 从类路径加载资源
     * @param resource 类路径当中的文件名
     * @return 指向资源文件的InputStream输入流
     */
    public static InputStream getMyResourceAsStream(String resource){
        return ClassLoader.getSystemClassLoader().getResourceAsStream(resource);
    }
}

第二步:定义SqlSessionFactoryBuilder类

参考测试程序,知道要获得SqlSession对象需要创建SqlSessionFactory,而SqlSessionFactory又是通过SqlSessionFactoryBuilder的build方法返回,所以需要定义一个MySqlSessionFactoryBuilder类,提供一个build方法,返回MySqlSessionFactory对象

/**
 * MySqlSessionFactory构建器对象,通过bulid方法解析Mybatis的XML配置文件,创建SqlSessionFactory
 */
public class MySqlSessionFactoryBuilder {

    public MySqlSessionFactoryBuilder() {
    }
    /**
     * 解析mybatis的XML配置文件,来构建MySqlSessionFactory对象
     * @param is 指向配置文件的一个输入流
     * @return MySqlSessionFactory
     */
    public MySqlSessionFactory bulid(InputStream is){
  
        return null;
    }

第三步:定义SqlSessionFactory类

在bulid这个方法中我们需要解析XML文件,而mybatis中的核心配置文件的基本信息有数据源、事务管理器、SQL映射。
事务管理需要用到Connection,而Connection是从配置文件dataSource标签来的,所以在JDBC事务管理器需要数据源属性
所以SqlSessionFactory这个类只需要两个属性一个是事务管理器属性和SQL映射属性
SQL映射在配置文件中可能有多个,所以需要一个集合进行存储。

/**
 * MySqlSessionFactory对象:
 *          一般一个数据库对应一个MySqlSessionFactory
 *          通过MySqlSessionFactory获取SqlSession,开启会话
 *          一个MySqlSessionFactory对象能够开启多个SqlSession会话
 */
public class MySqlSessionFactory {
    /**
     * 事务管理器属性,对应XML配置文件的transactionManager标签
     */
    private MyTransaction transactionManager;
    /**
     * 存放Sql语句的Map集合。
     * key存SQL-id
     * value存对应的SQL标签对象
     * MyMappedStatement是SQL映射的实体类
     */
    private Map<String ,MyMappedStatement> mappedStatementMap;
}

第四步:定义JDBC事务管理器

mybatis的事务管理有两种:JDBC事务管理器和MANAGED事务管理器
需要可以随意切换,需要定义一个事务管理器接口,让JDBC事务管理器和MANAGED事务管理器去实现这个接口,实现里面的方法就行了,这里我们只实现JDBC事务管理器
定义⼀个接⼝,然后每⼀个具体的事务管理器都实现这个接⼝。

/**
 * 事务管理器接口。提供管理事务的方法
 * 所有事务管理器都应该实现这个接口
 */
public interface MyTransaction {
    /**
     * 提交事务
     */
    void commit();

    /**
     * 回滚事务
     */
    void rollback();

    /**
     * 关闭事务
     */
    void close();

    /**
     * 真正开启数据库连接
     */
    void openConnention();
    /**
     * 获取Connention
     */
    Connection getConnection();
}

/**
 * JDBC事务管理器
 */
public class JdbcTransaction implements MyTransaction{
    /**
     * 事务管理需要用到Connection,而Connection是从配置文件dataSource标签来的,所以需要数据源属性
     * 数据源属性,对应XML配置文件的dataSource标签
     */
    private DataSource dataSource;
    /**
     * 自动提交标志
     * true表示自动提交
     * false表示不采用自动提交
     */
    private boolean autoCommit;
    private Connection connection;
    @Override
    public Connection getConnection() {
        return connection;
    }

    public JdbcTransaction() {
    }

    public JdbcTransaction(DataSource dataSource, boolean autoCommit) {
        this.dataSource = dataSource;
        this.autoCommit = autoCommit;
    }

    @Override
    public void commit() {
        try {
            connection.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void rollback() {
        try {
            connection.rollback();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void close() {
        try {
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void openConnention() {
        if (connection == null) {
            try {
                connection = dataSource.getConnection();
                connection.setAutoCommit(autoCommit);
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}


第五步:定义数据源类

mybatis的数据源有三种:UNPOOLED、POOLED以及JNDI
这里只需实现UNPOOLED
实现数据源需要去实现DataSource接口,并实现里面的方法

/**
 * 数据源实现类:UNPOOLED
 * 不使用连接池,每一次都新建Connection对象。
 */
public class UnPooledDataSource implements DataSource {
    private String url;
    private String username;
    private String password;

    public UnPooledDataSource() {
    }

    /**
     * 创建一个数据源对象,通过构造方法注册驱动
     * @param driver
     * @param url
     * @param username
     * @param password
     */
    public UnPooledDataSource(String driver, String url, String username, String password) {
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        this.url = url;
        this.username = username;
        this.password = password;
    }

    @Override
    public Connection getConnection() throws SQLException {
        Connection connection = DriverManager.getConnection(url, username, password);
        return connection;
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }
}

第六步:定义MyMappedStatement类

/**
 * 只是一个普通的java类,封装了SQL标签
 * 一个MyMappedStatement对象对应一个SQL标签
 */
public class MyMappedStatement {
    private String sql;//对应SQL配置文件的SQL语句
    /**
     * 映射结果集类型,只有select标签有这个属性,其他标签没有是null,对应SQL配置文件的resultType属性
     */
    private String resultType;

    public MyMappedStatement() {
    }

    public MyMappedStatement(String sql, String resultType) {
        this.sql = sql;
        this.resultType = resultType;
    }

    public String getSql() {
        return sql;
    }

    public void setSql(String sql) {
        this.sql = sql;
    }

    public String getResultType() {
        return resultType;
    }

    public void setResultType(String resultType) {
        this.resultType = resultType;
    }

    @Override
    public String toString() {
        return "MyMappedStatement{" +
                "sql='" + sql + '\'' +
                ", resultType='" + resultType + '\'' +
                '}';
    }
}

第七步:完善SqlSessionFactory类

/**
 * MySqlSessionFactory对象:
 *          一般一个数据库对应一个MySqlSessionFactory
 *          通过MySqlSessionFactory获取SqlSession,开启会话
 *          一个MySqlSessionFactory对象能够开启多个SqlSession会话
 */
public class MySqlSessionFactory {
    /**
     * 事务管理器属性,对应XML配置文件的transactionManager标签
     */
    private MyTransaction transactionManager;
    /**
     * 存放Sql语句的Map集合。
     * key存SQL-id
     * value存对应的SQL标签对象
     */
    private Map<String ,MyMappedStatement> mappedStatementMap;

    public MySqlSessionFactory() {
    }

    public MySqlSessionFactory(MyTransaction transactionManager, Map<String, MyMappedStatement> mappedStatementMap) {
        this.transactionManager = transactionManager;
        this.mappedStatementMap = mappedStatementMap;
    }

    public MyTransaction getTransactionManager() {
        return transactionManager;
    }

    public void setTransactionManager(MyTransaction transactionManager) {
        this.transactionManager = transactionManager;
    }

    public Map<String, MyMappedStatement> getMappedStatementMap() {
        return mappedStatementMap;
    }

    public void setMappedStatementMap(Map<String, MyMappedStatement> mappedStatementMap) {
        this.mappedStatementMap = mappedStatementMap;
    }

第八步:完善SqlSessionFactoryBuilder中的build⽅法

开始解析配置文件
1.使用Dom4j创建reader对象
2.通过类加载器获取Myabtis的配置文件输入流,这个已经在工具类封装了,而且是通过参数传过来了。
3.读XML文件,返回一个文档对象document
4.对标签进行处理
4.1获取默认的环境,因为将来有可能配置多个环境
(1)获取environments的default的值
(2)通过defalt获取默认environment
4.2处理默认环境的配置
(1)获取事务管理器标签
(2)获取数据源标签
(3)对数据源和事务管理器进行处理,创建数据源对象和事务管理器对象
5.获取所有的Mapper标签,进行处理,构建map集合
6.最后创建出一个MySqlSessionFactory对象

/**
 * MySqlSessionFactory构建器对象,通过bulid方法解析Mybatis的XML配置文件,创建SqlSessionFactory
 */
public class MySqlSessionFactoryBuilder {

    public MySqlSessionFactoryBuilder() {
    }
    /**
     * 解析mybatis的XML配置文件,来构建MySqlSessionFactory对象
     * @param is 指向配置文件的一个输入流
     * @return MySqlSessionFactory
     */
    public MySqlSessionFactory bulid(InputStream is){
        MySqlSessionFactory factory = null;
        MyTransaction transactionManager = null;
        Map<String ,MyMappedStatement> mappedStatementMap = null;
        DataSource dataSource = null;
        try {
            //1.使用Dom4j创建reader对象
            SAXReader reader = new SAXReader();
            //2.通过类加载器获取Myabtis的配置文件输入流,这个已经在工具类封装了
            //3.读XML文件,返回一个文档对象document
            Document document = reader.read(is);
            //4.对标签进行处理
            //4.1获取默认的环境,因为将来有可能配置多个环境
            //(1)获取environments的default的值
            //通过标签匹配路径获取节点,这样就获取到了environments这个节点,返回是Node,Element是Node的子类,方法更多,使用更方便
            Element environments = ((Element) document.selectSingleNode("/configuration/environments"));
            //通过attributeValue获取default的值
            String defalt = environments.attributeValue("default");
            //(2)通过defalt获取默认environment
            Element environment = (Element) document.selectSingleNode("/configuration/environments/environment[@id='"+defalt+"']");

            //4.2处理默认环境的配置
            //(1)获取事务管理器标签
            //获取environment下的transactionManager标签,element用来获取孩子节点
            Element transactionManagerElt = environment.element("transactionManager");
            //获取事务管理器的类型
            //String transactionType = transactionManagerElt.attributeValue("type");

            //(2)获取数据源标签
            Element dataSourceElt = (Element) environment.element("dataSource");
            //String dataSourceType = dataSourceElt.attributeValue("type");
            //(3)对数据源和事务管理器进行处理
            //通过数据源标签获取数据源
            dataSource = getDataSource(dataSourceElt);
            //通过数据源和事务管理器标签,获取事务管理器
            transactionManager = getTransactionManager(transactionManagerElt,dataSource);


            //5.获取所有的Mapper标签,进行处理
            List<Node> mappers = document.selectNodes("//mapper");

            //通过mapper标签,处理射信息
            mappedStatementMap = getMappedStatement(mappers);



            factory = new MySqlSessionFactory(transactionManager,mappedStatementMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return factory;
    }

    /**
     * 解析所有的SQLMapper.xml文件,然后构建map集合
     * @param mappers 所有mapper的List集合
     * @return
     */
    private Map<String, MyMappedStatement> getMappedStatement(List<Node> mappers) {
        Map<String, MyMappedStatement> mappedStatementMap = new HashMap<>();
        mappers.forEach(mapper -> {
            Element mapperElt = (Element) mapper;
            //获取resource映射路径
            String resource = mapperElt.attributeValue("resource");
            //通过映射路径解析SQLMapper.xml文件
            SAXReader reader = new SAXReader();
            try {
                Document document = reader.read(MyResouces.getMyResourceAsStream(resource));
                Element SQLmapper = ((Element) document.selectSingleNode("mapper"));
                String namespace = SQLmapper.attributeValue("namespace");
                List<Element> elements = SQLmapper.elements();
                elements.forEach(element -> {
                    String id = element.attributeValue("id");
                    String sqlid = namespace + "." + id;
                    String resultType = element.attributeValue("resultType");
                    //获取文本,去掉前后空格
                    String sql = element.getTextTrim();

                    MyMappedStatement myMappedStatement = new MyMappedStatement(sql,resultType);
                    mappedStatementMap.put(sqlid,myMappedStatement);
                });
            } catch (DocumentException e) {
                e.printStackTrace();
            }
        });
        return mappedStatementMap;
    }

    /**
     * 获取数据源对象
     * @param dataSourceElt 数据源标签
     * @return
     */
    private DataSource getDataSource(Element dataSourceElt) {
        DataSource dataSource = null;
        Map<String,String> map = new HashMap<>();
        List<Element> propertys = dataSourceElt.elements();
        propertys.forEach(propertysElt -> {
            String name = propertysElt.attributeValue("name");
            String value = propertysElt.attributeValue("value");
            map.put(name,value);
        });
        //获取数据源的类型,有可能是小写,所以要把它统一变成大写,trim()去掉前后空格
        String dataSourceType = dataSourceElt.attributeValue("type").trim().toUpperCase();
        if (Const.UN_POOLED_DATASOURCE.equals(dataSourceType)) {//UNPOOLED
            dataSource = new UnPooledDataSource(map.get("driver"),map.get("url"),map.get("username"),map.get("password"));
        }else if (Const.POOLED_DATASOURCE.equals(dataSourceType)){//POOLED
            dataSource = new PooledDataSource();
        }else if (Const.JNDI_DATASOURCE.equals(dataSourceType)){//JNDI
            dataSource = new JNDIDataSource();
        }
        return dataSource;
    }

    /**
     * 获取事务管理器对象
     * @param transactionManagerElt 事务管理器标签
     * @param dataSource 数据源对象
     * @return
     */
    private MyTransaction getTransactionManager(Element transactionManagerElt, DataSource dataSource) {
        MyTransaction transaction = null;
        String transactionType = transactionManagerElt.attributeValue("type");
        if (Const.JDBC_TRANSACTION.equals(transactionType)) {//JDBC,默认开启事务
            transaction = new JdbcTransaction(dataSource,false);
        }else if (Const.MANAGED_TRANSACTION.equals(transactionType)){//MANAGED
            transaction = new ManagedTransaction();
        }
        return transaction;
    }
}

第九步:添加openSession⽅法获取会话对象

/**
     * 获取SQL会话对象
     * @return
     */
    public MySqlSession openSession(){
        //打开连接
        transactionManager.openConnention();
        MySqlSession sqlSession = new MySqlSession(this);
        return sqlSession;
    }

第十步:创建会话类MySqlSession

这里只提供两个方法insert和selectOne

/**
 * 专门负责执行SQL语句的会话对象
 */
public class MySqlSession {
    MySqlSessionFactory factory;

    public MySqlSession() {
    }

    public MySqlSession(MySqlSessionFactory factory) {
        this.factory = factory;
    }
    //以下就是JDBC代码了,这里只写insert和selectOne

    /**
     * 执行insert语句,向数据库表当中插入记录
     * @param sqlid xml的要执行sql的id
     * @param pojo 插入的数据
     * @return
     */
    public int insert(String sqlid,Object pojo){
        int count = 0;
        try {
            Connection connection = factory.getTransactionManager().getConnection();
            String sql = factory.getMappedStatementMap().get(sqlid).getSql();
            //把#{}变成占位符?
            String newsql = sql.replaceAll("#\\{[0-9A-Za-z_$]*}", "?");
            PreparedStatement ps = connection.prepareStatement(newsql);
            int fromIndex = 0;
            int index = 1;
            while (true) {
                int jingIndex = sql.indexOf("#", fromIndex);
                if (jingIndex < 0) {
                    break;
                }
                int youkuohaoIndex = sql.indexOf("}", fromIndex);
                String properName = sql.substring(jingIndex + 2, youkuohaoIndex).trim();
                fromIndex = youkuohaoIndex + 1;
                //调用对应的get的方法
                String getMethodName = "get" + properName.toUpperCase().charAt(0) + properName.substring(1);
                Method getMethod = pojo.getClass().getDeclaredMethod(getMethodName);
                Object properValue = getMethod.invoke(pojo);
                ps.setString(index,properValue.toString());
                index++;
            }
            count = ps.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return count;
    }


    /**
     * 执行查询语句,返回一个对象。该方法只适合返回一条记录的sql语句。
     * @param sqlId
     * @param param
     * @return
     */
    public Object selectOne(String sqlId, Object param){
        Object obj = null;
        try {
            Connection connection = factory.getTransactionManager().getConnection();
            MyMappedStatement mappedStatement = factory.getMappedStatementMap().get(sqlId);
            String sql = mappedStatement.getSql();
            String newsql = sql.replaceAll("#\\{[a-zA-Z0-9_$]*}", "?");
            PreparedStatement ps = connection.prepareStatement(newsql);
            // 给占位符传值
            ps.setString(1, param.toString());
            // 查询返回结果集
            ResultSet rs = ps.executeQuery();
            // 要封装的结果类型。
            String resultType = mappedStatement.getResultType();
            // 从结果集中取数据,封装java对象
            if (rs.next()) {
                // 获取resultType的Class
                Class<?> resultTypeClass = Class.forName(resultType);
                // 调用无参数构造方法创建对象
                obj = resultTypeClass.newInstance(); // Object obj = new User();
                /*
                解决问题的关键:将查询结果的列名作为属性名。
                列名是id,那么属性名就是:id
                列名是name,那么属性名就是:name
                 */
                ResultSetMetaData rsmd = rs.getMetaData();
                int columnCount = rsmd.getColumnCount();
                for (int i = 0; i < columnCount; i++) {
                    String propertyName = rsmd.getColumnName(i + 1);
                    // 拼接方法名
                    String setMethodName = "set" + propertyName.toUpperCase().charAt(0) + propertyName.substring(1);
                    // 获取set方法
                    Method setMethod = resultTypeClass.getDeclaredMethod(setMethodName, String.class);
                    // 调用set方法给对象obj属性赋值
                    setMethod.invoke(obj, rs.getString(propertyName));
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }


    public void commit(){
        factory.getTransactionManager().commit();
    }
    public void rollback(){
        factory.getTransactionManager().rollback();
    }
    public void close(){
        factory.getTransactionManager().close();
    }
}

测试

数据库创建一个表,这个表只能是Varchar类型,因为手写的这个Mybatis框架没有进行自动类型的推断,对传过来的数据统一看作是字符串处理

请添加图片描述
配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
        	<!--这里只能是JDBC,其他没有实现-->
            <transactionManager type="JDBC"/>
            <!--这里只能是UNPOOLED,其他没有实现-->
            <dataSource type="UNPOOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mydbtest"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="DeptMapper.xml"/>
    </mappers>
</configuration>

DeptMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="dept">
    <!--id是这条语句的唯一标识。这个id就代表了这条SQL语句-->
    <insert id="insertDept">
        insert into t_mybatis
        value(#{deptno},#{dname},#{loc})
    </insert>
    <select id="selectById" resultType="com.pojo.Dept">
        select * from t_mybatis where deptno=#{deptno}
    </select>
</mapper>

实体类

public class Dept {
    //private  deptno;
    private String deptno;
    private String dname;
    private String loc;

    public Dept() {
    }

    public Dept(String deptno, String dname, String loc) {
        this.deptno = deptno;
        this.dname = dname;
        this.loc = loc;
    }
/* public Integer getDeptno() {
        return this.deptno;
    }*/

    /*public void setDeptno(Integer deptno) {
        this.deptno = deptno;
    }*/

    @Override
    public String toString() {
        return "Dept{" +
                "deptno='" + deptno + '\'' +
                ", dname='" + dname + '\'' +
                ", loc='" + loc + '\'' +
                '}';
    }

    public String getDeptno() {
        return deptno;
    }

    public void setDeptno(String deptno) {
        this.deptno = deptno;
    }

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        this.dname = dname;
    }

    public String getLoc() {
        return loc;
    }

    public void setLoc(String loc) {
        this.loc = loc;
    }
}

测试程序

    @Test
    public void testInsert(){
        MySqlSessionFactoryBuilder sqlSessionFactoryBuilder = new MySqlSessionFactoryBuilder();
        MySqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.bulid(MyResouces.getMyResourceAsStream("mybatis-config.xml"));
        MySqlSession sqlSession = sqlSessionFactory.openSession();
        Dept dept = new Dept("10","销售部","北京");
        sqlSession.insert("dept.insertDept",dept);
        sqlSession.commit();
        sqlSession.close();
    }
    @Test
    public void testSelectOne(){
        MySqlSessionFactoryBuilder sqlSessionFactoryBuilder = new MySqlSessionFactoryBuilder();
        MySqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.bulid(MyResouces.getMyResourceAsStream("mybatis-config.xml"));
        MySqlSession sqlSession = sqlSessionFactory.openSession();
        Object o = sqlSession.selectOne("dept.selectById", "10");
        System.out.println(o);
        sqlSession.commit();
        sqlSession.close();
    }

insert测试,测试成功通过
请添加图片描述
数据库数据插入成功
请添加图片描述
selectOne测试,测试成功,显示数据
请添加图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于遗传算法卡车无人机旅行推销员问题(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Leetcode刷题111. 二叉树的最小深度

给定一个二叉树&#xff0c;找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明&#xff1a;叶子节点是指没有子节点的节点。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;2 示例 2&#xff1a; 输入…

Python_机器学习_算法_第7章_7.拓展知识

Python_机器学习_算法_第7章_7.拓展知识 文章目录Python_机器学习_算法_第7章_7.拓展知识7.拓展知识7.1. 其他距离公式1 标准化欧氏距离2 余弦距离3 汉明距离【了解】4 杰卡德距离【了解】5 马氏距离【了解】7.2.再议数据分割1 留出法2 交叉验证法2.1 交叉验证法基本介绍2.2 KF…

ARM发布Cortex-X3和Cortex-A715

快速链接: . &#x1f449;&#x1f449;&#x1f449; 个人博客笔记导读目录(全部) &#x1f448;&#x1f448;&#x1f448; 付费专栏-付费课程 【购买须知】: 【精选】ARMv8/ARMv9架构入门到精通-[目录] &#x1f448;&#x1f448;&#x1f448; ARM公司发布了第二代 AR…

x86 smbus 下挂eeprom不能写问题

目录 背景 分析 驱动影响 SPD register 接口 只读 修改验证 总结 背景 x86 smbus上下挂一个eeprom&#xff0c;只能读取&#xff0c;不能写入。 写入命令采用&#xff1a; i2cset -y -f 0 0x50 0 0x33 即向总线0 下的0x50 地址的eeprom偏移量0 写入数据0x33&#xff0c; 命令…

哈夫曼树原理及Java编码实现

文章目录前言一、哈夫曼树原理二、哈夫曼编码&#xff08;Java题解&#xff09;参考资料前言 所有博客文件目录索引&#xff1a;博客目录索引(持续更新) 源代码&#xff1a;Gitee—Huffman.java、Github—Huffman.java 一、哈夫曼树原理 对于哈夫曼树的构造以及权值计算原理…

Java语言高级-10MySQL-第2节MySQL安装与使用

2、MySQL数据库软件 1、安装 详细见视频 2、卸载 1、去mysql的安装目录找到my.ini文件 “复制datadir “C:/programData/MySQL/MySQL Server 5.5/Data” 2、卸载MySQL 控制面板->程序卸载&#xff0c;但是此时并没有卸载干净 3、删除C:/ProgramData目录下得MySQL文件夹 注意…

java 内部类

小镇做题家 前段时间很火的一个话题“小镇做题家”&#xff0c;我没有具体了解&#xff0c;我以为是在鼓励一些努力拼搏的人。 某一天&#xff0c;禁不住好奇&#xff0c;我打开了百度百科&#xff0c;看了看小镇做题家的解释 就是指一些村里或者小镇的人&#xff0c;通过学习…

模板和泛型编程(上)

目录函数模板泛型编程函数模板概念及原理函数模板的实例化函数模板的匹配原则类模板类模板实例化函数模板 泛型编程 泛型编程&#xff08;Generic Programming&#xff09;最初提出时的动机很简单直接&#xff1a;发明一种语言机制&#xff0c;能够帮助实现一个通用的标准容器…

猿创征文|Python迭代器、生成器、装饰器、函数闭包

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 Python迭代器、生成器、装饰器、函数闭包1. 迭代器 iterator☞迭代器协议☞Python中的for循环2. 生成器…

C语言qsort()函数针对:整型、单个字符、字符串、结构体,超详细讲解(多维度分析举例,小白一看就懂!!!!!)

目录 一、前言 二、qsort()函数 &#x1f351;qsort()函数简介 &#x1f349;qsort()函数中整型、double型、字符型的应用 &#x1f4a6;整型 &#x1f4a6; double型 &#x1f4a6;字符排序 &#x1f34e;qsort()函数在字符串中的应用 &#x1f4a6;在字符串中按首字母…

Android NDK开发基础

文章目录cmake语法基础cmake添加日志&#xff1a;cmake增加宏字符串比较cmake在build.gradle中传递编译参数到cmake通过javah生成native对应的c头文件jni和java之间字符串的相互操作JavaVM和JNIEnv字符串的编码native方法静态注册和动态注册静态注册动态注册extern cC中STATIC和…

SpringCloud Alibaba-Sentinel保姆级教程

文章目录1、Sentinel前奏1.1、服务雪崩效应1.2、常见容错方案1、隔离2、超时3、限流4、熔断5、降级1.3、常见容错组件1、Hystrix2、Resilience4J3、Sentinel2、Sentinel入门2.1、什么是Sentinel2.2、实战编码1、安装Sentinel服务端2、微服务引入Sentinel2.3、Sentinel流控模式1…

YOLOv5蒸馏 | 知识蒸馏理论篇 | 1/2

之前在《一文搞懂【知识蒸馏】【Knowledge Distillation】算法原理》这篇文章中介绍过一些知识蒸馏的原理,这篇博文将会着重介绍目标检测领域的知识蒸馏原理。 文章目录 1.《Object detection at 200 Frames Per Second》1.1 蒸馏难点1.2 蒸馏损失1.3 实验结果2. 《Learning E…

计算机毕业设计ssm+vue基本微信小程序的体检预约小程序

项目介绍 我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;体检预约系统小程序被用户普遍使用&#xff0c;为方便用户…

【前端】CSS(1) —— CSS的基本语法和一些简单的选择器

JavaEE传送门JavaEE 网络原理——网络层与数据链路层 【前端】HTML入门 —— HTML的常见标签 目录CSS基本语法注释引入方式内部样式内联样式外部样式代码风格样式格式样式大小写空格规范CSS 选择器标签选择器类选择器id 选择器通配符选择器复合选择器后代选择器子选择器并集选…

文件包含漏洞和hash破解

介绍 Windows是当今世界最主要的操作系统&#xff0c;因为它易于使用的GUI可访问性。大约85%的市场份额已成为攻击的关键操作系统。此外&#xff0c;大多数组织使用Active Directory来设置其Windows域网络。微软聘请NTLM&#xff08;New Technology LAN Manager&#xff09;和…

Pico Neo3 4VR游戏下载地址及十大好玩游戏推荐

大家好&#xff0c;杰克今天为大家分享的是VR一体机游戏。 说到VR一体机&#xff0c;我们首先想到的一定是国产之光pico啦&#xff0c;picovr被认为是国内最被看好的VR一体机&#xff0c;有望在国内取代红极一时的OculusQuest&#xff0c;填补这块市场的空白。OculusQuest将6D…

#Primavera Unifier:关于零代码/低代码平台特点【2/3】

在之前对Unifier的介绍中&#xff0c;我提到了Unifier应用的一个非常关键的特征&#xff0c;及零代码快速配置使用&#xff0c;而为了更好的介绍Oracle Primavera Unifier 的零代码特点&#xff0c;以下我将通过3篇内容来逐一介绍零代码/低代码平台的特点。 前面介绍到了零代码…

Opencv项目实战:14 手势控制音量

目录 0、项目介绍 1、项目展示 2、项目搭建 3、项目的代码与讲解 4、项目资源 5、项目总结 0、项目介绍 本篇与上一篇有很多联系&#xff0c;大家可以看看这篇Opencv项目实战&#xff1a;13 手部追踪&#xff0c;我们将根据上一节的内容&#xff0c;进行一个拓展。本篇你…