mybatis学习笔记

简介

1、持久层框架
2、maven仓库获取
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.6</version>
</dependency>

构建mybatis项目

1、编写mybatis 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>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

2、编写mybatis工具类

public class MybatisUtils {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        InputStream inputStream = null;
        try {
            String resource = "mybatis-config.xml";
            inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public static SqlSession getSqlSession(){
        return  sqlSessionFactory.openSession();
    }
}

3、编写dao层接口

public interface UserMapper {
    public List<User> getUserList();
}

4、编写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">

<mapper namespace="com.tang.dao.UserMapper">
    <select id="getUserList" resultType="com.tang.pojo.User">
    select * from user
  </select>
</mapper>

5、测试类

public class UserDaoTest {

@Test
public void test(){
    SqlSession sqlSession =null;
    try {
        sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        sqlSession.close();
    }
}

}

maven资源过滤

 <!-- 资源过滤-->
<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

CRUD操作

parameterType:参数类型
resultType:返回类型

查询用户通过id:

<select id="getUserById" parameterType="int" resultType="com.tang.pojo.User"> select * from user where id=#{id} </select>

增加用户

注意:增删改需要提交事务
<insert id="addUser" parameterType="com.tang.pojo.User"> insert into user(id,name,pwd) values(#{id},#{name},#{pwd}) </insert>

    public void addUser(){
    SqlSession sqlSession =null;
    try {
        sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.addUser(new User(9,"hahha","123"));
        sqlSession.commit();
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        sqlSession.close();
    }
	}

配置解析

configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)

1、environments(环境配置)

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


注:1、在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]")
2、有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]"):
3、MyBatis默认使用事务管理器JDBC 连接池POOLED

2、properties(属性)

创建db.properties文件

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
username=root
password=root

在mybatis-config.xml中引入properties文件

<configuration>
<properties resource="db.properties"/>
....
</configuration>
当两个文件同一字段,优先使用外部配置文件。

3、类型别名(typeAliases)

<typeAliases>
  <typeAlias alias="Author" type="domain.blog.Author"/>
  ....
</typeAliases>

也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
<typeAliases>
  <package name="domain.blog"/>
</typeAliases>

在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author;若有注解,则别名为其注解值
@Alias("author")
public class Author {
    ...
}

4、设置(settings)

设置名	描述	有效值
cacheEnabled	全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。	true | false	true
lazyLoadingEnabled	延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。	true | false
logImpl	指定 MyBatis 所用日志的具体实现,未指定时将自动查找。	SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING	未设

5、映射器(mappers)

<!-- 使用相对于类路径的资源引用 -->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
</mappers>


<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
</mappers>
注意:1、使用此方法,接口必须和他的mapper配置文件名相同
	 2、接口和他的mapper配置文件必须在同一包下


<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>
注意:1、使用此方法,接口必须和他的mapper配置文件名相同
	 2、接口和他的mapper配置文件必须在同一包下

### 6、作用域(Scope)和生命周期 ###
SqlSessionFactoryBuilder:这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。
SqlSessionFactory:SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
SqlSession:SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。

结果映射resultMap

resultMap 元素是 MyBatis 中最重要最强大的元素。




然后在引用它的语句中设置 resultMap 属性就行了
<select id="selectUsers" resultMap="userResultMap">
  select user_id, user_name, hashed_password
  from some_table
  where id = #{id}
</select>

日志

作用:出现异常排错
以前:sout debug

SLF4J 
LOG4J 【掌握】
LOG4J2  
JDK_LOGGING 
COMMONS_LOGGING 
STDOUT_LOGGING 【掌握】
NO_LOGGING

标准日志STDOUT_LOGGING 输出
<settings>
  <setting name="logImpl" value="STDOUT_LOGGING "/>
</settings>

LOG4J

1、导包
2、创建log4j.properties配置文件
设置
log4j.rootLogger = debug,stdout,D,E
 
 输出信息到控制抬 
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
 
输出DEBUG 级别以上的日志到=E://logs/error.log
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = E://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG 
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
 
输出ERROR 级别以上的日志到=E://logs/error.log
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =E://logs/error.log 
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR 
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

使用注解开发

@Param()
基本类型的参数需要加上
引用类型不用加
我们在sql中的引用就是@Param()中设定的属性名

多对一查询

按照查询嵌套处理

<!--思路:
1、查询所有学生的信息
2、根据查询出来学生信息的tid,寻找对应的老师-->
<select id="getStudent" resultType="StudentTeacher">
    select * from student
</select>
<resultMap id="StudentTeacher" type="Student">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>

<select id="getTeacher" resultType="Teacher">
    select * from teacher where id=#{id}
</select>

</mapper>

按照结果嵌套处理

<!--    按照结果嵌套处理-->
<select id="getStudent2" resultType="StudentTeacher2">
    select s.id sid,s.name sname,t.name tname
    from student s,teacher t
    where s.tid = t.id
</select>

<resultMap id="StudentTeacher2" type="Student">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <association property="teacher"  javaType="Teacher">
        <result property="name" column="tname"/>
    </association>
</resultMap>

一对多查询

例如:一个老师有多个学生

按照结果嵌套查询

 <!--    按照结果嵌套处理-->
<select id="getTeacher" resultType="StudentTeacher">
select s.id sid,s.name sname,t.name tname,t.id tid
from student s,teacher t
where s.tid = t.id
</select>

<resultMap id="StudentTeacher" type="teacher">
    <result property="id" column="tid"/>
    <result property="name" column="tname"/>
<!--  复杂的属性,我们需要单独处理 对象association  集合:collection
javaType指定属性的类型
ofType指定集合中,泛型的类型-->
    <collection property="Students"  ofType="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="tid" column="tid"/>
    </collection>
</resultMap>

按照查询嵌套处理

<!--    按照查询嵌套处理-->
<select id="getTeacher" resultType="StudentTeacher2">
select * from teacher where id = #{tid}
</select>

<resultMap id="StudentTeacher2" type="Teacher">
    <collection property="Students"  column="id" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId"/>
</resultMap>

<select id="getStudentByTeacherId" resultType="Student">
    select * from student where tid=#{tid}
</select>

小结:
1、关联 多对一 association
2、集合 一对多 collection
3、javaType & ofType
javatype:指定实体类属性类型
ofType:指定映射到list或者集合中的泛型类型

动态sql

if

这条语句提供了可选的查找文本功能。如果不传入 “title”,那么所有处于 “ACTIVE” 状态的 BLOG 都会返回;如果传入了 “title” 参数,那么就会对 “title” 一列进行模糊查找并返回对应的 BLOG 结果
<select id="findActiveBlogWithTitleLike"
  resultType="Blog">
  SELECT * FROM BLOG
  WHERE state = ‘ACTIVE’
  <if test="title != null">
	AND title like #{title}
  </if>
</select>

choose、when、otherwise

有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
<select id="findActiveBlogLike"
 resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <choose>
<when test="title != null">
  AND title like #{title}
</when>
<when test="author != null and author.name != null">
  AND author_name like #{author.name}
</when>
<otherwise>
  AND featured = 1
</otherwise>
  </choose>
</select>

where

where 元素只会在子元素有返回内容的情况下才插入 “WHERE” 子句。
若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
<select id="findActiveBlogLike"
 resultType="Blog">
  SELECT * FROM BLOG
  <where>
<if test="state != null">
     state = #{state}
</if>
<if test="title != null">
    AND title like #{title}
</if>
<if test="author != null and author.name != null">
    AND author_name like #{author.name}
</if>
  </where>
</select>

set

set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号
<update id="updateAuthorIfNecessary">
  update Author
    <set>
      <if test="username != null">username=#{username},</if>
      <if test="password != null">password=#{password},</if>
      <if test="email != null">email=#{email},</if>
      <if test="bio != null">bio=#{bio}</if>
    </set>
  where id=#{id}
</update>

和 where 元素等价的自定义 trim 元素为:

...

与 set 元素等价的自定义 trim 元素:

...

foreach

动态 SQL 的另一个常见使用场景是对集合进行遍历

它允许你指定一个集合(list)
index 是当前迭代的序号
item 的值是本次迭代获取到的元素

缓存

默认情况下,只启用了本地的会话缓存(一级缓存),它仅仅对一个会话中的数据进行缓存。
要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:
基本上就是这样。这个简单语句的效果如下:

映射语句文件中的所有 select 语句的结果将会被缓存。
映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
缓存不会定时进行刷新(也就是说,没有刷新间隔)。

二级缓存

1、开启默认缓存(一般默认开启,单独写出来,起提示作用)



2、在当前mapper.xml中,添加标签

小结:
1、只要开启了二级缓存,在同一个mapper下生效,二级缓存只能针对一个namespace有效。。
2、所有数据先放入一级缓存中,当一级缓存关闭或提交时,自动放入二级缓存。

原理

第一次查询先看二级缓存里面有没有,在看一级缓存里面,没有就查询。

资料来源:B站秦疆老师(遇见狂神说)
https://space.bilibili.com/95256449

原文地址:https://www.cnblogs.com/xiaolaodi1999/p/13463284.html