从零再学mybatis

从零再学mybatis
直观的来说mybatis有以下特点

  1. 使用灵活,sql高度可定制
  2. 性能优化易操作
  3. 入门门槛低,只需要掌握sql语法即可
  4. 实现与接口相分离
  5. orm 框架(半自动,需要手动编写sql)

mybatis如此优秀,易上手,性能可以有效优化,使得其成为非常流行的数据库后端框架之一.

现在针对mybatis提出以下问题:

  1. mybatis 如何将.xml 文件mapper接口绑定到一起产生对象的?
  2. mybatis的缓存是如何管理的

mybatis 基本环境搭建:

需要的文件

  1. 数据库脚本
  2. pojo 类 User
  3. UserMapper 接口,UserMapper.xml
  4. mybatis.jar 包
  5. mybatis-config.xml
  6. db.properties

具体步骤

  1. sql 脚本
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) CHARACTER SET utf8mb4 DEFAULT NULL,
  `password` varchar(32) CHARACTER SET utf8mb4 DEFAULT NULL,
  `sex` varchar(10) CHARACTER SET utf8mb4 DEFAULT NULL,
  `description` varchar(255) CHARACTER SET utf8mb4 DEFAULT '',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;

  1. User 类
public class User {
    private int id;
    private String name;
    private String sex;
    private String description;
    private String password;

   
    public User() {
    }

    public User(String name, String sex, String description) {
        this.name = name;
        this.sex = sex;
        this.description = description;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", description='" + description + '\'' +
                '}';
    }
    ... 省略getter/setter
    }
  1. UserMapper.java 接口 以及UserMapper.xml 文件

public interface UserMapper {
    void insert(User user);
    User getById(int id);
}

<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="top.forethought.framework.mybatis.dao.UserMapper">
    <resultMap type="top.forethought.framework.jdbctemplate.User" id="usermap">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="password" property="password"/>
        <result column="sex" property="sex"/>
        <result column="description" property="description"/>
    </resultMap>

    <select id="getById"  parameterType="int" resultMap="usermap">
        select * from user where id=#{id}
    </select>
    <insert id="insert">
        insert into user ( name,password, sex,description) values (
       #{name}, #{password},#{sex}, #{description}
        )
    </insert>



</mapper>
  1. pom.xml 依赖
 <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>${mybatis.version}3.2.8</version>
        </dependency>
         <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>${mybatis.spring.version}</version>
        </dependency>
  1. mybatis-config.xml
<?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>
    <properties resource="top/forethought/framework/configs/db.properties">


    </properties>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${jdbcUrl}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>


    <mappers>
        <mapper resource="top/forethought/framework/mybatis/mapper/UserMapper.xml"/>
    </mappers>
</configuration>

  1. db.properties ,配置具体的数据库参数,供xml文件中引用
username=noneroot
password=18142513872
jdbcUrl=jdbc:mysql://localhost:3306/test_index?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT
driver=com.mysql.jdbc.Driver

  1. 测试类 TestMapper.java

public class TestMapper {
    @Test
    public void testMybatis() throws IOException {

        String resource = "top/forethought/framework/configs/mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory =
                new SqlSessionFactoryBuilder().build(inputStream);

        SqlSession sqlSession=sqlSessionFactory.openSession();
        UserMapper mapper=  sqlSession.getMapper(UserMapper.class);
    User user=new User();
    user.setName("123");
    user.setSex("男");
    user.setDescription("这是人物描述"+System.currentTimeMillis());
    mapper.insert(user);
    System.out.println("查询来自数据库:"+mapper.getAll().toString());
    sqlSession.commit();// 如果不commit 是不能提交事务到数据库的
    sqlSession.close();
    }
}


  1. 测试效果

在这里插入图片描述

mybatis如何产生实实在在的mapper对象

先看最终结果

在这里插入图片描述显然最终得到的是实现了UserMapper 中接口方法的代理类

再看debug 过程

以下截图主要是为了记录执行流程
在这里插入图片描述MapperRegistry:看名字可以知道这是mapper注册器,所有mapper接口与相应实现xml文件绑定成功成功后会保存一条记录到knownMappers 之中
knownNappers ,是一个Map ,以接口名为key(比如这里是UsernMapper),
MapperProxyFactory 为val
即:记录了接口与mapper代理工厂之间的映射关系
在这里插入图片描述MapperProxyFactory: 有一个Map 来保存 接口中的方法到mapper.xml 中的具体实现(MapperMethod)的映射关系
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述MapperMethod:
在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述

大体流程如下:

MapperRegistry 的getMapper 方法中,调用了MapperProxyFactory的newInstance 方法获取到
根据接口生成的代理对象

在这里插入图片描述生成的代理对象应该使用的是jdk的动态代理
调用mapper.insert() 方法时,可以发现
在这里插入图片描述

结论

  1. mapper 与xml的绑定,使用了工厂模式产生代理对象(实现了接口)
  2. 采用了jdk动态代理(InvocationHandler)
  3. 使用反射创建代理对象
  4. 主要参与的类有MapperRegistry(根据接口找代理MapperProxyFactory),MapperProxyFactory(造代理对象)

mybatis 如何配置或者是管理缓存

可以查看打印输出的sql语句来判断是否使用了缓存

  1. 配置sql输出

在mybatis-config.xml 的中添加以下内容(注意位置,会有提示,按照提示处理标签顺序即可,这是由dtd来约束的)

 <settings>
        <!-- 打印查询语句 -->
        <setting name="logImpl" value="STDOUT_LOGGING" />

    </settings>
  1. 修改测试类代码

public class TestMapper {
    @Test
    public void testMybatis() throws IOException {

        String resource = "top/forethought/framework/configs/mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory =
                new SqlSessionFactoryBuilder().build(inputStream);

        SqlSession sqlSession=sqlSessionFactory.openSession();
        UserMapper mapper=  sqlSession.getMapper(UserMapper.class);
//    User user=new User();
//    user.setName("123");
//    user.setSex("男");
//    user.setDescription("这是人物描述"+System.currentTimeMillis());
//    mapper.insert(user);
        // 连续在相同条件下查询两次数据库,发现输出的sql只有一句
        System.out.println("查询来自数据库:"+mapper.getAll().toString());
        System.out.println("查询来自数据库:"+mapper.getAll().toString());
   // sqlSession.commit();// 如果不commit 是不能提交事务到数据库的
    sqlSession.close();
    }
}

输出:
在这里插入图片描述尝试关闭mybatis缓存
mybatis-config.xml 的settings添加

 <setting name="cacheEnabled " value="false"/>

测试效果:
发现还是只是输出了一句,难道是打开方式不对!!!
cacheEnabled:是缓存的全局配置,如果关闭,那么其他有关缓存的配置都将是无效的

Globally enables or disables any caches configured in any mapper under this configuration.

参数配置错了,应该配置 localCacheScope属性,可以配置cache范围是SESSION还是STATEMENT
SESSION:表示同一个session,所有的查询都会被缓存,那么相同的查询执行第二遍,那么就是去缓存取数据了,而不是再次去数据库查询
STATEMENT:表示每一个语句都是去数据库查询

MyBatis uses local cache to prevent circular references and speed up repeated nested queries. By default (SESSION) all queries executed during a session are cached. If localCacheScope=STATEMENT local session will be used just for statement execution, no data will be shared between two different calls to the same SqlSession

 <setting name="localCacheScope" value="STATEMENT"/>

效果:

在这里插入图片描述

疑问:

可能对SESSION会有疑问了,如果是设置为SESSION,同一个session内指向两次相同查询的之间再执行一条插入语句,那么第二次查询还是会从缓存取吗?
测试结果发现,这样是执行了两次数据库查询
在这里插入图片描述

更多的settings 相关配置,传送

其他小问题:

Cause: java.sql.SQLException: Incorrect string value: ‘\xE7\x94\xB7’ for column ‘sex’ at row 1

原因:数据库字符编码问题
在这里插入图片描述

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值