Mybatis


Mybatis

DAO(Data Access Objects)数据持久层对象

获得Mybatis

maven:

org.mybatis mybatis 3.5.2

github:

https://github.com/mybatis/mybatis-3/releases

中文文档:

https://mybatis.org/mybatis-3/zh/index.html

1.2持久层

数据持久化

  • 持久化就是将数据的程序在持久状态和瞬时状态转换的过程
  • 内存:断电即失
  • 数据库:io文件持久化

1.3持久化

Dao层,Service层,Controller层

  • 完成持久化工作的代码块
  • 层界限十分明显

搭建环境

创建普通maven项目

看idea的maven是否默认,如果默认改回

删除src,作为父工程

导入依赖

(mysql)

(Mybatis)

(junit)

连数据库

创建模块

编写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">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="$&#123;driver&#125;"/>
        <property name="url" value="$&#123;url&#125;"/>
        <property name="username" value="$&#123;username&#125;"/>
        <property name="password" value="$&#123;password&#125;"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

编写工具类

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

//sqlSessionFactory-->sqlSession
public class MybatisUtils &#123;
    private static  SqlSessionFactory sqlSessionFactory;
    static &#123;
        try &#123;
            //使用mybatis
            String resource="mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
           sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        &#125;catch (IOException e)&#123;
            e.printStackTrace();
        &#125;
    &#125;

    public  static SqlSession getSqlSession()&#123;
      return sqlSessionFactory.openSession();
     &#125;
&#125;

编写实体类

public class User &#123;
    private  int id;
    private String name;
    private String pwd;

    public User(int id, String name, String pwd) &#123;
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    &#125;

    public User() &#123;
    &#125;

    public int getId() &#123;
        return id;
    &#125;

    public void setId(int id) &#123;
        this.id = id;
    &#125;

    public String getName() &#123;
        return name;
    &#125;

    public void setName(String name) &#123;
        this.name = name;
    &#125;

    public String getPwd() &#123;
        return pwd;
    &#125;

    public void setPwd(String pwd) &#123;
        this.pwd = pwd;
    &#125;

    @Override
    public String toString() &#123;
        return "User&#123;" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '&#125;';
    &#125;
&#125;

Dao接口

import com.zf.pojo.User;

import java.util.List;

public interface UserDao &#123;
    List<User>  getUserList();
&#125;

接口实现类

由原来的userDaoImpl转变为一个mapper.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">
<!--namespace 绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.zf.dao.UserDao">
    <select id="getUserList" resultType="com.zf.pojo.User">
    select * from mybatis.user
  </select>
</mapper>

大致流程:

  • 写工具类
  • xml
  • 实体类
  • 接口
  • xml写sql语句
  • 测试

2.CRUD

1.namespace

namespace中的包名要和Dao和Mapper接口包名保持一致

2.select

选择查询语句

  • id:就是对应namespace中的方法名
  • resultType:sql语句执行的返回值
  • parameterType:参数类型

1.编写接口

2.编写对应的Mapper的sql语句

3.测试(增删改记得提交事务)

记得看map存储数据进行查询

image-20210912214712705

3.配置解析

1.核心配置文件

mybatis-config.xml

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:

2.环境配置environments

mybatis可以配置成适应多种环境

不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。

所以,如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。而如果是三个数据库,就需要三个实例,依此类推,记起来很简单:

  • 每个数据库对应一个 SqlSessionFactory 实例

  • environments 元素定义了如何配置环境。

    <environments default="development">
      <environment id="development">
        <transactionManager type="JDBC">
          <property name="..." value="..."/>
        </transactionManager>
        <dataSource type="POOLED">
          <property name="driver" value="$&#123;driver&#125;"/>
          <property name="url" value="$&#123;url&#125;"/>
          <property name="username" value="$&#123;username&#125;"/>
          <property name="password" value="$&#123;password&#125;"/>
        </dataSource>
      </environment>
    </environments>
    

    注意一些关键点:

    • 默认使用的环境 ID(比如:default=”development”)。
    • 每个 environment 元素定义的环境 ID(比如:id=”development”)。
    • 事务管理器的配置(比如:type=”JDBC”)。默认事务管理器
    • 数据源的配置(比如:type=”POOLED”)。连接池

    默认环境和环境 ID 顾名思义。 环境可以随意命名,但务必保证默认的环境 ID 要匹配其中一个环境 ID。

3.属性properties

编写一个配置文件

db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8
username=root
password=123456

在核心配置文件中映入

<properties resource="db.properties">  
</properties>

这里注意是否正确

同样也可以在properties里面填数据

<!--引入外部配置文件-->
<properties resource="db.properties">
  <property name="username" value="root"></property>
    <property name="password" value="123456"></property>
</properties>

这样在db.properties不用写username和password也可以读取到数据库中的内容

  • 可以直接引入外部文件
  • 可以在其中添加一些属性
  • 如果两个文件中有同一字段,优先使用外部配置文件

4.类型别名

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:

<typeAliases>
    <typeAlias type="com.zf.pojo.User"  alias="User"></typeAlias>
</typeAliases>

也可以指定一个包名,mybatis会在包名下面搜索需要的Javabean

image-20210913201316765

第一种自定义别名,第二种不可以

image-20210913201433343

5.设置

image-20210913201847166

6.其他配置

image-20210913202137578

7.配置文件

image-20210913202529322

方式2:

接口和它的mapper配置文件必须同名

接口和它的mapper配置文件必须在同一个包下

方式三:

image-20210913202741924

接口和它的mapper配置文件必须同名

接口和它的mapper配置文件必须在同一个包下

8.生命周期和作用域

image-20210913203900634

4.解决属性名与字段之间的问题

修改一个实体类里面的属性

如pwd改为password

image-20210913214521464

2.使用resultMap

结果集映射

id name pwd

id name password

<resultMap id="UserMap" type="User">    <result column="id"  property="id"></result>    <result column="name"  property="name"></result>    <result column="pwd"  property="password"></result></resultMap>    

5.日志

5.1日志工厂

如果一个数据库操作出现了异常,需要排错

曾经:sout,debug

现在:日志工厂

image-20210914185557254

  • SLF4J |
  • LOG4J | (掌握)
  • LOG4J2 |
  • JDK_LOGGING |
  • COMMONS_LOGGING |
  • STDOUT_LOGGING | (掌握)
  • NO_LOGGING

在mybatis具体使用哪个日志

<settings>    <setting name="logImpl" value="STDOUT_LOGGING"/></settings>

image-20210914190436790

LOG4J使用

1.导包

<!-- https://mvnrepository.com/artifact/log4j/log4j --><dependency>    <groupId>log4j</groupId>    <artifactId>log4j</artifactId>    <version>1.2.17</version></dependency>

2.创建配置文件log4j.properties

log4j.rootLogger=DEBUG,console,file#控制台输出的相关设置log4j.appender.console=org.apache.log4j.ConsoleAppenderlog4j.appender.console.Target=System.outlog4j.appender.console.Threshold=DEBUGlog4j.appender.console.layout=org.apache.log4j.PatternLayoutlog4j.appender.console.layout.ConversionPattern=[%c]-%m%n#文件输出的相关配置log4j.appender.file=org.apache.log4j.RollingFileAppenderlog4j.appender.file.File=./log/kuang.loglog4j.appender.file.MaxFileSize=10mblog4j.appender.file.Threshold=DEBUGlog4j.appender.file.layout=org.apache.log4j.PatternLayoutlog4j.appender.file.layout.ConversionPattern=[%p][%d&#123;yy-MM-dd&#125;[%c]%m%n#日志输出级别log4j.logger.org.mybatis=DEBUGlog4j.logger.java.sql=DEBUGlog4j.logger.java.sql.Statement=DEBUGlog4j.logger.java.sql.ResultSet=DEBUGlog4j.logger.java.sql.PreparedStatement=DEBUG

3.设置

<settings>    <setting name="logImpl" value="LOG4J"/></settings>

4.如何使用

在要使用log4j的;类中导包(阿帕奇的)

image-20210914200242880

6.分页

使用limit分页

语法:select * from user limit startIndex,pageSize;

select * from user limit 3;

使用mybatis进行分页,核心sql

1.定义接口

  List<User>  getUserByLimit(Map<String,Integer> map);

2.注册xml

<select id="getUserByLimit" parameterType="map" resultMap="UserMap">    select  * from mybatis.user limit #&#123;startIndex&#125;,#&#123;pageSize&#125;</select>

3.测试

 public void testlimit()&#123;    SqlSession sqlSession = MybatisUtils.getSqlSession();    UserMapper mapper = sqlSession.getMapper(UserMapper.class);    Map<String,Integer>  map=new HashMap<String, Integer>();    map.put("startIndex",0);            map.put("pageSize",2);    List<User> userList = mapper.getUserByLimit(map);    for (User user : userList) &#123;        System.out.println(user);    &#125;    sqlSession.close();&#125;

6.1rowbound实现分页

7.使用注解开发

接口里面

@Select("select * from user")List<User> getUsers();

然后配置xml里面

<mappers>    <mapper class="com.zf.dao.UserMapper"></mapper></mappers>

注解实现crud

在创建工具类时自动提交事务

public  static SqlSession getSqlSession()&#123;  return sqlSessionFactory.openSession(true); &#125;

关于@param注解

基本类型或者String类型需加上

引用类型不需要加

8.多对一处理

image-20210917203019627

查询多个学生对应一个老师

student实体类

package com.zf.pojo;import lombok.Data;@Datapublic class Student &#123;    private  int id;    private String name;    private Teacher teacher;&#125;

teacher实体类

package com.zf.pojo;import lombok.Data;@Datapublic class Teacher &#123;    private int id;    private String name;&#125;

studentMapper接口

package com.zf.dao;import com.zf.pojo.Student;import java.util.List;public interface StudentMapper &#123;    public List<Student> getStudent();    public List<Student> getStudent2();&#125;

注意在mybatis-config里面做实体类别名

<typeAliases>    <typeAlias type="com.zf.pojo.Student"  alias="Student"></typeAlias>    <typeAlias type="com.zf.pojo.Teacher"  alias="Teacher"></typeAlias></typeAliases>
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"        "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.zf.dao.StudentMapper"><!--按照结果处理-->    <select id="getStudent2" resultMap="StudentTeacher2">        select s.id sid,s.name sname,t.name tname         from student s,teacher t        where tid=t.id;    </select> <resultMap id="StudentTeacher2" type="Student">     <result property="id" column="sid"></result>     <result property="name" column="sname"></result>     <association property="teacher" column="tid" javaType="Teacher">         <result property="name" column="tname"></result>     </association> </resultMap>    <select id="getStudent" resultMap="StudentTeacher">     -- select s.id,s.name,t.name from  student s,teacher t where s.id=t.id;select * from student;    </select>    <resultMap id="StudentTeacher" type="Student">        <result property="id" column="id"></result>        <result property="name" column="name"></result>        <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"></association>    </resultMap>    <select id="getTeacher" resultType="Teacher">        select * from  teacher where id= #&#123;id&#125;    </select></mapper>
//测试类public class MyTest&#123;    public static void main(String[] args) &#123;        SqlSession sqlSession = MybatisUtils.getSqlSession();        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);        List<Student> student = mapper.getStudent();        for (Student student1 : student) &#123;            System.out.println(student1);        &#125;        sqlSession.close();    &#125;    @Test    public void test()&#123;        SqlSession sqlSession = MybatisUtils.getSqlSession();        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);        List<Student> student = mapper.getStudent2();        for (Student student1 : student) &#123;            System.out.println(student1);        &#125;        sqlSession.close();    &#125;&#125;

一对多处理

一个老师对应多个学生

package com.zf.pojo;import lombok.Data;@Datapublic class Student &#123;    private  int id;    private String name;    private int tid;&#125;
import lombok.Data;import java.util.List;@Datapublic class Teacher &#123;    private int id;    private String name;    private List<Student> students;&#125;

教师mapper接口

public interface  TeacherMapper &#123;  //  List<Teacher> getTeacher();    Teacher  getTeacher(@Param("tid") int id);&#125;
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"        "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.zf.dao.TeacherMapper">    <select id="getTeacher" resultMap="TeacherStudent">        select s.id sid, s.name sname, t.name tname,t.id tid        from student s,teacher t        where s.tid=t.id and t.id=#&#123;tid&#125;;    </select>        <resultMap id="TeacherStudent" type="Teacher">        <result property="id" column="tid"></result>        <result property="name" column="tname"></result>        <collection property="students" ofType="Student">            <result property="id" column="sid"></result>            <result property="name"  column="sname"></result>            <result property="tid" column="tid"></result>        </collection>    </resultMap></mapper>
public class MyTest &#123;    @Test    public void test()&#123;        SqlSession sqlSession = MybatisUtils.getSqlSession();        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);        Teacher teacher = mapper.getTeacher(1);            System.out.println(teacher);        sqlSession.close();    &#125;&#125;

image-20210918160438173

9.动态sql

10.缓存

image-20210919145604954

一级缓存

  • 一级缓存也叫本地缓存sqlSession
  • 与数据库同一次会话期间查询到的数据会放到本地缓存中
  • 以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库

测试步骤:

1.开始日志

2.测试在一个SQLSession中查询两次相同的记录

3.查看日志输出

缓存失效的情况:

1.查询不同的东西

2.增删改东西是可能会改变原来数据,所以必定会刷新缓存

3.查询不同的mapper.xml

4..手动清理缓存

sqlSession.clearCache

一级缓存是默认开启的,只在一次sqlSession中有效,也就是拿到连接到关闭这个连接这个区间段,一级缓存相当于一个map

二级缓存

image-20210919163835147

image-20210919165253319

image-20210919165311880

image-20210919170046217


文章作者: 蛰伏
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 蛰伏 !
  目录