文章目录

  • 一、Mybatis
    • 1、Mybatis简介
      • 1.1 什么是Mybatis
      • 1.2 获取Mybatis
    • 2、第一个Mybatis
      • 2.1 搭建环境
        • 2.1.1 搭建数据库
        • 2.1.2 新建项目
      • 2.2 创建一个模块
        • 2.2.1 编写核心配置文件
        • 2.2.2 编写工具类
      • 2.3 编写代码
        • 2.3.1 可能会遇到的错误
        • 2.3.2 实体类
        • 2.3.3 Dao接口
        • 2.3.4 接口实现类
        • 2.3.5 单元测试
    • 3、类作用域
    • 4、CURD
      • 4.1 select
      • 4.2 insert
      • 4.3 update
      • 4.4 delete
      • 4.4 模糊查询
    • 5、核心配置文件解析
      • 5.1 属性(properties)
      • 5.2 设置(settings)
      • 5.3 类型别名(typeAliases)
      • 5.4 环境配置(environments)
        • 5.4.1 事务管理器
        • 5.4.2 数据源
      • 5.5 映射器(mappers)
    • 6、mapper配置文件解析
      • 6.1 select标签
      • 6.2 insert, update 和 delete
      • 6.3 结果映射resultMap
        • 6.3.1解决属性名和字段名不一致的问题
        • 6.3.2 resultMap标签的属性
        • 6.3.3 resultMap标签的子标签
      • 6.4 sql片段
    • 7、日志
      • 7.1 日志工厂
      • 7.2 LOG4J
    • 8、分页的实现
    • 9、使用注解开发
      • 9.1 基本使用
      • 9.2 CRUD
      • 9.3 关于@Param("id")
    • 10、lombok(偷懒专用)
    • 11、多对一association
    • 12、一对多collection
    • 13、 动态sql
      • 13.1 准备数据
      • 13.2 if使用
      • 13.3 choose、when、otherwise
      • 13.4 trim、where、set
      • 13.5 Foreach
    • 14、缓存
      • 14.1 一级缓存
      • 14.2 二级缓存
      • 14.3 自定义缓存ehcache
    • 15、作业

一、Mybatis

官方文档:https://mybatis.org/mybatis-3/zh/index.html

1、Mybatis简介

1.1 什么是Mybatis

  • MyBatis 是一款优秀的持久层框架

  • 它支持自定义 SQL、存储过程以及高级映射

  • MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作

  • MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录

1.2 获取Mybatis

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.11</version>
</dependency>

2、第一个Mybatis

2.1 搭建环境

2.1.1 搭建数据库

CREATE DATABASE mybatis;
USE mybatis;
CREATE TABLE `user` (`id` INT(20) NOT NULL,`name` VARCHAR(30) DEFAULT NULL,`pwd` VARCHAR(30) DEFAULT NULL,PRIMARY KEY(`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `user`(`id`,`name`,`pwd`) VALUES
(1,'张三','123123'),
(2,'李四','111111'),
(3,'王五','121212');

2.1.2 新建项目

  1. 创建一个普通的maven项目

  2. 删除src目录使其变成一个父工程

  3. 导入依赖

    1. <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.49</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.11</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency>
      

2.2 创建一个模块

之后我们的项目都是一个个模块

2.2.1 编写核心配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf-8"/><property name="username" value="root"/><property name="password" value="123456"/></dataSource></environment></environments><mappers><mapper resource="com/daban/dao/UserMapper.xml"/></mappers>
</configuration>

2.2.2 编写工具类

package com.daban.utils;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;public class MybatisUtils {private static SqlSessionFactory sqlSessionFactory;static {try {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);} catch (IOException e) {e.printStackTrace();}}public static SqlSession getSqlSession(){return sqlSessionFactory.openSession();}
}

2.3 编写代码

2.3.1 可能会遇到的错误

  • org.apache.ibatis.binding.BindingException: Type interface com.daban.dao.UserDao is not known to the MapperRegistry.

    意思是没有在mybatis的配置文件中注册mapper,需要在配置文件中添加注册

    <mappers><mapper resource="com/daban/dao/UserMapper.xml"/>
    </mappers>
    
  • org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.io.IOException: Could not find resource com/daban/dao/UserMapper.xml

    不能找到mapper.xml文件,因为在构建的时候没有导出该文件,如下代码到pom中可以解决

<build><resources><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes><filtering>true</filtering></resource></resources>
</build>
  • org.xml.sax.SAXParseException; lineNumber: 5; columnNumber: 14; 1 字节的 UTF-8 序列的字节 1 无效。

是因为xml文件中的注释使用了中文,去掉即可,或者将encoding="UTF-8"改为encoding=“UTF8”(原因不明)

2.3.2 实体类

package com.daban.pojo;public class User {private int id;private String name;private String pwd;public User() {}public User(int id, String name, String pwd) {this.id = id;this.name = name;this.pwd = pwd;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPwd() {return pwd;}public void setPwd(String pwd) {this.pwd = pwd;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", pwd='" + pwd + '\'' +'}';}
}

2.3.3 Dao接口

package com.daban.dao;import com.daban.pojo.User;import java.util.List;public interface UserDao {List<User> getUserList();
}

2.3.4 接口实现类

(由之前的实现类转变成一个Mapper配置文件)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace绑定一个接口,相当于实现一接口-->
<mapper namespace="com.daban.dao.UserDao">
<!--    id就是接口中的方法名字-->
<!--    resultType返回类型要写类型的全名--><select id="getUserList" resultType="com.daban.pojo.User">select * from mybatis</select>
</mapper>

2.3.5 单元测试

package com.daban.dao;import com.daban.pojo.User;
import com.daban.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;import java.util.List;public class UserMapperTest {@Testpublic void test(){//获取sqlSessionSqlSession sqlSession = MybatisUtils.getSqlSession();//得到UserDao的MapperUserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> userList = mapper.getUserList();for (User user: userList) {System.out.println(user);}sqlSession.close();}
}

3、类作用域

作用域 备注
SqlSessionFactoryBuilder 最佳作用域是方法作用域(也就是局部方法变量)
SqlSessionFactory 最佳作用域是应用作用域 想象为数据库连接池
SqlSession 最佳的作用域是请求或方法作用域 连接到连接池的一个请求,用完关闭

4、CURD

记住,在增删改的时候需要提交事务才可以生效sqlSession.commit();

4.1 select

1、编写接口

//通过id查询用户
User getUserById(int id);

2、编写对应mapper中的sql语句

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

3、测试

public void getUserById(){SqlSession sqlSession = MybatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);User userById = mapper.getUserById(1);System.out.println(userById);sqlSession.close();
}

4.2 insert

1、编写接口

//增加一个用户
void addUser(User user);

2、编写对应mapper中的sql语句

<insert id="addUser" parameterType="com.daban.pojo.User">insert into mybatis.user values(#{id},#{name},#{pwd})
</insert>

3、测试

public void addUser(){SqlSession sqlSession = MybatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);mapper.addUser(new User(5,"嫦娥","333333"));//增删改必须要提交事务sqlSession.commit();sqlSession.close();
}

4.3 update

1、编写接口

//修改一个用户
void updateUser(User user);

2、编写对应mapper中的sql语句

<update id="updateUser" parameterType="com.daban.pojo.User">update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id}
</update>

3、测试

public void updateUser(){SqlSession sqlSession = MybatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);mapper.updateUser(new User(5,"大圣","888888"));sqlSession.commit();sqlSession.close();
}

4.4 delete

1、编写接口

//删除一个用户
void deleteUser(User user);

2、编写对应mapper中的sql语句

<delete id="deleteUser" parameterType="com.daban.pojo.User">delete from mybatis.user where id=#{id}
</delete>

3、测试

public void deleteUser(){SqlSession sqlSession = MybatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);mapper.deleteUser(new User(5));sqlSession.commit();sqlSession.close();
}

4.4 模糊查询

1、编写接口

//通过name查询用户
List<User> getUserByName(String name);

2、编写对应mapper中的sql语句

<select id="getUserByName" resultType="com.daban.pojo.User" parameterType="string" >select * from mybatis.user where name like #{name}
</select>

3、测试

public void getUserByName(){SqlSession sqlSession = MybatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> userList = mapper.getUserByName("%张%");for (User user: userList) {System.out.println(user);}sqlSession.close();
}

5、核心配置文件解析

首先配置文件中标签是有顺序的,写反会报错

properties>settings>typeAliases>typeHandlers>objectFactory>objectWrapperFactory>reflectorFactory>plugins>environments>databaseIdProvider>mappers

5.1 属性(properties)

引入一个配置文件,使mybatis的核心配置文件可以引用该配置文件里面的参数

<properties resource="config.properties"><!--标签里也可以有属性,和外部文件里面写的属性,效果一样,只是有一个优先级--><property name="username" value="root"/><property name="password" value="123456"/>
</properties>

获取值的方式

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

如果一个属性在不只一个地方进行了配置,那么,MyBatis 将按照下面的顺序来加载:

  • 首先读取在 properties 元素体内指定的属性。
  • 然后根据 properties 元素中的 resource 属性读取类路径下属性文件,或根据 url 属性指定的路径读取属性文件,并覆盖之前读取过的同名属性。
  • 最后读取作为方法参数传递的属性,并覆盖之前读取过的同名属性。

因此,通过方法参数传递的属性具有最高优先级,resource/url 属性中指定的配置文件次之,最低优先级的则是 properties 元素中指定的属性。

5.2 设置(settings)

这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为

官网查找https://mybatis.org/mybatis-3/zh/configuration.html

5.3 类型别名(typeAliases)

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

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

可以通过包来起别名,包下的所有实体类,都可以使用类名的首字母小写来代替全名,给实体类加注解,可以diy

<typeAliases><package name="com.daban.pojo"/>
</typeAliases>

5.4 环境配置(environments)

<environments default="development">默认使用的环境<environment id="development">定义的环境标识,可随意标识,保证默认的环境 ID 要匹配其中一个环境 ID<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>

5.4.1 事务管理器

在 MyBatis 中有两种类型的事务管理器(也就是 type=“[JDBC|MANAGED]”)

如果你正在使用 Spring + MyBatis,则没有必要配置事务管理器,因为 Spring 模块会使用自带的管理器来覆盖前面的配置

5.4.2 数据源

有三种内建的数据源类型(也就是 type=“[UNPOOLED|POOLED|JNDI]”),

UNPOOLED– 这个数据源的实现会每次请求时打开和关闭连接。虽然有点慢,但对那些数据库连接可用性要求不高的简单应用程序来说,是一个很好的选择

POOLED(常用)– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间

JNDI – 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的数据源引用

5.5 映射器(mappers)

告诉 MyBatis 到哪里去找到sql语句

方式一、【推荐使用】

<!-- 使用相对于类路径的资源引用 -->
<mappers><mapper resource="com/daban/dao/UserMapper.xml"/>
</mappers>

方式二、

<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers><mapper class="com.daban.dao.UserMapper"/>
</mappers>

注意点:

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

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

方式三、

<!-- 将包内的映射器接口全部注册为映射器 -->
<mappers><package name="com.daban.dao"/>
</mappers>

注意点:

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

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

方式四、【不建议使用】

<!-- 使用完全限定资源定位符(URL) -->
<mappers><mapper url="file:///var/mappers/AuthorMapper.xml"/>
</mappers>

6、mapper配置文件解析

6.1 select标签

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

select元素的属性

<selectid="selectPerson"                      dao接口中的方法名字parameterType="int"                    参数的类全限定名或别名。这个属性是可选的parameterMap="deprecated"              废弃了resultType="hashmap"                   返回结果的类全限定名或别名,如果是集合,写集合泛型resultMap="personResultMap"            对实体类和字段名字不一样时的处理,结果映射flushCache="false"                     每次sql执行,都刷新清除一二级缓存useCache="true"                        开启二级缓存timeout="10"                           在抛出异常之前,驱动程序等待数据库返回请求结果的秒数fetchSize="256"                        尝试让驱动程序每次批量返回的结果行数等于这个设置值statementType="PREPARED"                 可选 STATEMENT,PREPARED 或 CALLABLEresultSetType="FORWARD_ONLY">

6.2 insert, update 和 delete

<insert id="insertAuthor">insert into Author (id,username,password,email,bio)values (#{id},#{username},#{password},#{email},#{bio})
</insert><update id="updateAuthor">update Author setusername = #{username},password = #{password},email = #{email},bio = #{bio}where id = #{id}
</update><delete id="deleteAuthor">delete from Author where id = #{id}
</delete>

属性

<insertkeyProperty=""                     设置自增主键的字段keyColumn=""useGeneratedKeys=""                开启自增主键timeout="20">

6.3 结果映射resultMap

ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了

6.3.1解决属性名和字段名不一致的问题

方式一、起别名

<select id="getUserById" resultType="com.daban.pojo.User" parameterType="int" >select user_id as id,user_name,user_pwd from mybatis.user where id = #{id}
</select>

方式二、使用resultMap

<resultMap id="userResultMap" type="User"><id property="id" column="user_id" /><result property="username" column="user_name"/><result property="password" column="user_password"/>
</resultMap>
<select id="getUserById" resultMap="userResultMap" parameterType="int" >select from mybatis.user where id = #{id}
</select>

6.3.2 resultMap标签的属性

标签 解释 备注
id 当前命名空间中的一个唯一标识,用于标识一个结果映射。 和select标签中的 resultMap绑定
type 类的完全限定名, 或者一个类型别名。 不用结果集映射时,select标签中的resultType的值
autoMapping 如果设置这个属性,MyBatis 将会为本结果映射开启或者关闭自动映射

6.3.3 resultMap标签的子标签

标签 解释 备注
constructor 用于在实例化类时,注入结果到构造方法中
id 标记出作为 ID 的结果可以帮助提高整体性能
result 注入到字段或 JavaBean 属性的普通结果
association 个复杂类型的关联;许多结果将包装成这种类型 相当于对象
collection 一个复杂类型的集合 相对于集合
discriminator 使用结果值来决定使用哪个

6.4 sql片段

这个元素可以用来定义可重用的 SQL 代码片段,以便在其它语句中使用

<sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql>
<include refid="userColumns"><property name="alias" value="t1"/></include>

7、日志

7.1 日志工厂

<settings><!--标准的日志工厂实现--><setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

设置里设置logImpl的值:

SLF4J

LOG4J(3.5.9 起废弃)

LOG4J2

JDK_LOGGING

COMMONS_LOGGING

STDOUT_LOGGING

NO_LOGGING

7.2 LOG4J

1、先导包

<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>

2、配置log4j的配置文件

resources下新建一个log4j.properties

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/logFile.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

3、使用

import org.apache.log4j.Logger;
Logger logger = Logger.getLogger(UserTest.class);//获得logger对象,参数为当前类的class
logger.info("我是info");
logger.debug("我是调试信息");
logger.error("我是error");

8、分页的实现

原理就是使用map来传递limit的参数

1、接口方法

List<User> getUserListLimit(Map<String,Object> map);

2、mapper配置文件

<mapper namespace="com.daban.dao.UserMapper"><resultMap id="userMap" type="user"><result property="password" column="pwd"/></resultMap><select id="getUserListLimit" resultMap="userMap" parameterType="map">select * from mybatis.user limit #{startIndex},#{pageSize}</select>
</mapper>

3、测试

public void test(){SqlSession sqlSession = MybatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);Map<String, Object> map = new HashMap<>();map.put("startIndex",2);map.put("pageSize",3);List<User> userList = mapper.getUserListLimit(map);for (User user : userList) {System.out.println(user);}sqlSession.close();
}

9、使用注解开发

9.1 基本使用

使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让本就复杂的 SQL 语句更加混乱不堪。 因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句

1、删除接口的mapper文件

2、接口中使用注解

@Select("select * from mybatis.user")
List<User> getUserList();

3、mybatis核心配置文件中使用类绑定

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

这样会发现无法进行结果集映射,这是使用注解的弊端

9.2 CRUD

SqlSession sqlSession = factory.openSession(true);//参数为是否自动提交,设置true后,不需要手动提交
//但是在使用注解时,会自动提交
public interface UserMapper {//查询所有@Select("select * from mybatis.user")List<User> getUserList();//查询,一个参数可以省略@Param@Select("select * from mybatis.user where id = #{id}")User getUserById(int id);//查询俩个参数,不能省略@Param@Select("select * from mybatis.user where id = #{id} and name = #{name}")User getUserByIdAndName(@Param("id") int id,@Param("name") String name);//增加@Select("insert into mybatis.user values(#{id},#{name},#{password})")void addUser(User user);//修改@Select("update mybatis.user set name=#{name},pwd=#{password} where id = #{id} ")void updateUser(User user);//删除@Select("delete from mybatis.user where id = #{id}")void deleteUser(User user);
}

9.3 关于@Param(“id”)

  • 基本参数类型和String类型需要加上
  • 引用类型不需要加
  • 如果只有一个基本类型,可以忽略,建议加上

10、lombok(偷懒专用)

1、idea中的plugin中安装lombok

2、导入lombok的jar包

<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version><scope>provided</scope>
</dependency>

3、使用

在实体类上加注解就行

@Getter//get方法
@Setter//set方法
@ToString//ToString方法
@EqualsAndHashCode//EqualsAndHashCode方法
@NoArgsConstructor//无参构造方法
@Data//以上都创建了@AllArgsConstructor//所有参数构造方法

11、多对一association

其实就是解决属性名和字段名不一致的问题,因为联表查询把其他表的字段放在了该表里,名称类型可能不一致

准备sql

CREATE TABLE teacher(`id`  INT(20) NOT NULL,`name` VARCHAR(30) DEFAULT NULL,PRIMARY KEY (`id`))ENGINE INNODB DEFAULT CHARSET=utf8;INSERT INTO teacher(`id`,`name`) VALUES(1,"张老师");CREATE TABLE student(`id` INT(20) NOT NULL,NAME VARCHAR(30) DEFAULT NULL,`tid` INT(10) DEFAULT NULL,PRIMARY KEY (`id`),FOREIGN KEY (`tid`) REFERENCES `teacher`(`id`)
)ENGINE INNODB DEFAULT CHARSET = utf8;INSERT INTO student(`id`,`name`,`tid`) VALUES(1,"小明",1);
INSERT INTO student(`id`,`name`,`tid`) VALUES(2,"小张",1);
INSERT INTO student(`id`,`name`,`tid`) VALUES(3,"小李",1);
INSERT INTO student(`id`,`name`,`tid`) VALUES(4,"小王",1);
INSERT INTO student(`id`,`name`,`tid`) VALUES(5,"小红",1);

实体类

@Data
public class Student {private int id;private String name;private Teacher teacher;
}
@Data
public class Teacher {private int id;private String name;
}

mapper文件

<mapper namespace="com.daban.dao.StudentMapper"><!--方式一、联表查询,嵌套方式--><resultMap id="getStudentListMap1" type="com.daban.pojo.Student"><result property="id" column="s_id"/><result property="name" column="s_name"/><association property="teacher" javaType="com.daban.pojo.Teacher" ><result property="name" column="t_name"/><result property="id" column="t_id"/></association></resultMap><select id="getStudentList1" resultMap="getStudentListMap1">select s.id as s_id,s.name as s_name,t.name as t_name,t.id as t_idfrom mybatis.student s , mybatis.teacher twhere t.id  = s.tid</select><!--方式二、联表查询,子查询方式--><resultMap id="getStudentListMap2" type="com.daban.pojo.Student"><result property="id" column="id"/><result property="name" column="name"/><association property="teacher" column="tid" javaType="com.daban.pojo.Teacher"select="getTeacherList"/></resultMap><select id="getStudentList2" resultMap="getStudentListMap2">select * from mybatis.student</select><select id="getTeacherList" resultType="com.daban.pojo.Teacher">select * from mybatis.teacher where id = #{id}</select></mapper>

12、一对多collection

其实就是解决属性名和字段名不一致的问题,因为联表查询把其他表的字段放在了该表里,名称类型可能不一致

实体类

@Data
public class Teacher {private int id;private String name;private List<Student> student;
}
@Data
public class Student {private int id;private String name;private int tid;
}

mapper文件

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.daban.dao.TeacherMapper"><!--方式一、联表查询,嵌套方式--><resultMap id="getTeacherListMap1" type="com.daban.pojo.Teacher"><result property="id" column="t_id"/><result property="name" column="t_name"/><collection property="student" column="t_id" ofType="com.daban.pojo.Student"><result property="id" column="s_id"/><result property="name" column="s_name"/><result property="tid" column="s_tid"/></collection></resultMap><select id="getTeacherList1" resultMap="getTeacherListMap1">select t.id as t_id,t.name as t_name,s.id as s_id,s.name as s_name,s.tid as s_tidfrom mybatis.teacher t,mybatis.student s where s.tid=t.id;</select><!--方式二、联表查询,子查询方式--><resultMap id="getTeacherListMap2" type="com.daban.pojo.Teacher"><result property="id" column="id"/><result property="name" column="name"/><collection property="student" column="id" ofType="com.daban.pojo.Student"javaType="ArrayList" select="getStudentList"/></resultMap><select id="getTeacherList2" resultMap="getTeacherListMap2">select * from mybatis.teacher</select><select id="getStudentList" resultType="com.daban.pojo.Student">select * from mybatis.student where tid = #{tid}</select>
</mapper>

13、 动态sql

13.1 准备数据

<settings><setting name="logImpl" value="STDOUT_LOGGING"/>开启数据库下划线命名和实体类属性驼峰命名的对应<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

根据不同的条件生成不同的sql语句

sql准备

CREATE TABLE blog(`id`  INT(50) NOT NULL,`title` VARCHAR(100) NOT NULL,`author` VARCHAR(30) NOT NULL,`create_time` DATETIME NOT NULL,`views` INT(30) NOT NULL)ENGINE INNODB DEFAULT CHARSET=utf8;

表中插入数据:

<insert id="addBlog" parameterType="blog">insert into mybatis.blog(`id`,`title`,`author`,`create_time`,`views`)values (#{id},#{title},#{author},#{createTime},#{views});
</insert>
public void addBlog(){SqlSession sqlSession = MybatisUtils.getSqlSession();BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);mapper.addBlog(new Blog(IDUtils.getID(),"庆祝二十大顺利召开","中央视频",new Date(),9999));mapper.addBlog(new Blog(IDUtils.getID(),"中纪委公布查处中央委员人数","中央视频",new Date(),500));mapper.addBlog(new Blog(IDUtils.getID(),"小学生捡到“十万元”组团交派出所","华商报",new Date(),2344));mapper.addBlog(new Blog(IDUtils.getID(),"浪漫同框!中国空间站飞越北京上空","华商报",new Date(),555));mapper.addBlog(new Blog(IDUtils.getID(),"中国要搞自给自足?发改委:误解","四川观察",new Date(),1234));sqlSession.commit();sqlSession.close();
}

13.2 if使用

注意map中的key要和if里面的title对应上(名称一致)

当sql语句中包含小于号时,不被识别。只能使用大于号,解决办法,前后颠倒要比较的值

<select id="queryBlogIf" resultType="blog" parameterType="map">select * from mybatis.blog where 1=1<if test="title!=null">and title like #{title}</if><if test="views!=null">and #{views} > views</if>
</select>
public void queryBlogIf(){SqlSession sqlSession = MybatisUtils.getSqlSession();BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);Map<String, Object> map = new HashMap<>();map.put("title","%中%");map.put("views",1000);List<Blog> blogs = mapper.queryBlogIf(map);for (Blog blog : blogs) {System.out.println(blog);}
}

13.3 choose、when、otherwise

类似与java的switch case语句:第一个满足条件后面都不执行了,都不满足执行otherwise

<select id="queryBlogChoose" resultType="blog" parameterType="map">select * from mybatis.blog where 1=1<choose><when test="title!=null">and title like #{title}</when><when test="author!=null">and #{author} = author</when><otherwise>and #{views} > views</otherwise></choose>
</select>
public void queryBlogChoose(){SqlSession sqlSession = MybatisUtils.getSqlSession();BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);Map<String, Object> map = new HashMap<>();
//        map.put("title","%中%");map.put("author","华商报");map.put("views",1000);List<Blog> blogs = mapper.queryBlogChoose(map);for (Blog blog : blogs) {System.out.println(blog);}}

13.4 trim、where、set

where 元素自动插入 “WHERE” 。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除

set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)

where和set都可以使用trim实现,只不过,trim更可以自定义

13.5 Foreach

<select id="queryBlogForeach" parameterType="map" resultType="blog">select * from mybatis.blog<where><foreach collection="viewsList" item="view" open="(" separator="or" close=")">views = #{view}</foreach></where></select>
public void queryBlogForeach(){SqlSession sqlSession = MybatisUtils.getSqlSession();BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);Map<String, Object> map = new HashMap<>();ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(9999);arrayList.add(2344);map.put("viewsList",arrayList);List<Blog> blogs = mapper.queryBlogForeach(map);for (Blog blog : blogs) {System.out.println(blog);}
}

14、缓存

查询的结果放在内存中,我们再次查询相同数据时,就可以走缓存,从而减少数据库的连接,减低资源损耗

经常查询且不经常改变的数据,可以使用缓存

创建实体类时,要实现序列化,这样对象才能被缓存,不然报错

mybatis默认两级缓存:

  • 一级缓存:默认开启,sqlsession级别的缓存
  • 二级缓存:需要手动开启,namespace级别的缓存

14.1 一级缓存

缓存失效的情况:

​ 1、查询不同的数据

​ 2、增删改操作,可能会改变原来的数据,所以必定会刷新缓存

​ 3、查询不同的mapper.xml

​ 4、手动清理缓存(sqlSession.clearCache();)

14.2 二级缓存

打开方式:在mapper文件中加入标签即可开启二级缓存

会话关闭时,就会将一级缓存中的数据保存到二级缓存,新的会话查询就会从二级缓存查询

14.3 自定义缓存ehcache

java的分布式缓存

1、先导包

<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
<dependency><groupId>org.mybatis.caches</groupId><artifactId>mybatis-ehcache</artifactId><version>1.2.2</version>
</dependency>

2、mapper文件中设置

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

3、增加配置文件ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"><!-- 磁盘缓存位置 --><diskStore path="java.io.tmpdir/ehcache"/><!-- 默认缓存 -->     <!--     name:缓存名称。     maxElementsInMemory:缓存最大个数。     eternal:对象是否永久有效,一但设置了,timeout将不起作用。     timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。     timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。     overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。     diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。     maxElementsOnDisk:硬盘最大缓存个数。     diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.     diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。     memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。     clearOnFlush:内存数量最大时是否清除。     --><defaultCachemaxElementsInMemory="10"eternal="false"timeToIdleSeconds="3600"timeToLiveSeconds="3600"overflowToDisk="true"memoryStoreEvictionPolicy="LRU"/><!-- deptrole缓存 --><cache name="deptrole"maxElementsInMemory="10"eternal="false"timeToIdleSeconds="86400"timeToLiveSeconds="86400"overflowToDisk="true"memoryStoreEvictionPolicy="LRU"/></ehcache>

15、作业

用mybatis重新写smbms项目

【SSM框架 一】Mybatis相关推荐

  1. JavaWeb学习之路——SSM框架之Mybatis(三)

    数据库配置和相关类创建看上篇:JavaWeb学习之路--SSM框架之Mybatis(二) https://blog.csdn.net/kuishao1314aa/article/details/832 ...

  2. SSM框架——使用MyBatis Generator自动创建代码

    SSM框架--使用MyBatis Generator自动创建代码 这是通过命令行, 不用ide插件. 若在IDEA中通过插件generator, 还可以参考另一篇: IDEA搭建Spring+Spri ...

  3. SSM框架-使用MyBatis Generator自动创建代码

    参考:http://blog.csdn.net/zhshulin/article/details/23912615 SSM搭建的时候用到MyBatis的代码自动生成的功能,由于MyBatis属于一种半 ...

  4. JavaWeb学习之路——SSM框架之Mybatis(二)

    1.简介: 框架: 是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种定义认为,框架是可被应用开发者定制的应用骨架.前者是从应用方面而后者是从目的方面给出的定义.它是一个半 ...

  5. SSM框架使用mybatis反向生成实体类、dao和映射文件

    2.1反向生成配置文件generatorConfig.xml 文件命名generatorConfig.xml为放在resources里 <generatorConfiguration> & ...

  6. SSM框架学习----Mybatis(2)

    Mybatis框架学习--中 Mybatis框架学习----(2) 1. Mybatis的自定义分析 1. 第一步 2. 第二步 3. 第三步 4. 第四步 5. 第五步 2. Mybatis实现CR ...

  7. SSM框架-实现Mybatis分页功能-foreknow_cms

    ##分页处理 分页 1.前台分页 2.数据库(后台)分页 3.存储过程 Orade (Rownum) Mysql(limit) sqlservier(Top N) 第一步 : 要在mybatis 核心 ...

  8. SSM框架专题-MyBatis框架老杜版从零入门笔记(下)

    七.MyBatis参数处理 7.1 单个简单参数 parameterType表示传入参数的类型,官方文档有很多别名可以参考 <insert id="insertStu" pa ...

  9. SSM框架之Mybatis同时传入多个对象及普通参数

    当传入多个文件时,mapper接口文件的方法参数要使用@param("xx")注释. 例子: mapper: //Student是对象,age是String类型. int getP ...

  10. mysql如何导入myeclisp中_MyEclipse搭建SSM框架(Spring+MyBatis+SpringMVC)

    如何使用CSS绘制一个响应式的矩形 背景: 最近因为需要用到绘制类似九宫格的需求,所以研究了一下响应式矩形的实现方案. 有如下几种方案: 使用js来设置元素的高度 使用vw单位  div {width ...

最新文章

  1. RandomAccessFile r rw rws rwd之间的区别
  2. Linux如何让命令提示符显示完整的路径
  3. Failed to set NvVAD endpoint as default Audio endpoint [0]
  4. mysql行锁和表锁
  5. Template methed
  6. C语言经典算法 1-10
  7. PHP的uniqid
  8. 在jsp页面实现保存登录用户名和密码
  9. 评奖.婚礼及“形而上”
  10. 二分类预测用的几个预测结果精确度计算方法
  11. 如何理解自然语言处理中的注意力机制? | 技术头条
  12. 《Java8实战》读书笔记
  13. springboot集成quartz
  14. 聊一聊数学中的基本定理(二)——算术基本定理的价值
  15. imagej对像素进行操作
  16. [数值计算-11]:多元函数求最小值 - 偏导数与梯度下降法Python法代码示例
  17. win10 ISO文件下载
  18. zabbix企业应用之自动语音报警平台
  19. 电脑用cmd命令将手机中的文件导入电脑中
  20. 【英语论文】英汉委婉语的文化价值和民族特质比较(节选)

热门文章

  1. MySQL50题-第6-10题
  2. 新C++(9):谈谈,翻转那些事儿
  3. 一起读Apache ServiceComb
  4. Apache Camel入门教程
  5. 高尔顿钉板实验是二项分布吗?
  6. 结合黏菌觅食行为的改进多元宇宙算法
  7. piechart 文档 android,Android饼图 PieChart
  8. 文件类型关联的文件图标
  9. android_驱动_qcom_【高通SDM660平台】(1) ---Bringup Guide
  10. WMS仓储管理系统在各种行业中,都有哪些作用