Mybatis原生使用

一、MyBatis初次使用

2.1 环境搭建步骤

MyBatis 的 API : https://mybatis.org/mybatis-3/zh/getting-started.html

1.引入依赖包

2.准备核心配置件

db.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://123.57.206.19:3306/demo?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username=root
password=123456

mybatis.xml

在resources下定义MyBatis的配置文件,无固定名,但大部分人使用 resources/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>
    <properties resource="db.properties"></properties>
<!--    <settings>-->
<!--        <setting name="logImpl" value="LOG4J"/>-->
<!--    </settings>-->
    <typeAliases>
        <!--给单个类起别名。 type:类型 alias:别名-->
        <typeAlias type="com.test.pojo.Student" alias="student"></typeAlias>
        <!--给指定包下所有类起别名。 别名=类名(不区分大小写)-->
        <package name="com.test.pojo"/>
    </typeAliases>

    <!--    配置mybaits中数据库连接环境-->
    <environments default="mysql">
        <environment id="mysql">
            <!--配置myabtis中事务 和 JDBC 保持一致-->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置连接数据库的4个元素, 底层采用的是数据库连接池的方式-->
            <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>
    <!--扫描mapper文件-->
    <mappers>
        <mapper resource="mapper/student.xml"></mapper>
    </mappers>
</configuration>

3.书写mapper文件

resources/**.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: 代表xml的名称,类似java包名-->
<mapper namespace="com.beiyou.dao.StudentDao">
   <!-- 查询所有学生 List<Student> selectAll()-->
    <!--
      select: 代表进行查询操作。
          id: 之前的方法名称,具有唯一性。
   resultType: 返回值类型。
               如果返回的是对象,直接书写对象类型的的完整名。
               如果是集合,书写的是集合的泛型
 parameterType: 参数类型,可以省略。
   -->
    <select id="selectAll" resultType="com.beiyou.entity.Student"  >
       select * from student
    </select>

</mapper>

非必需

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory><!--所在的目录-->
            <includes>
                <!--.xml 文件都会扫描到,包括子目录-->
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
       <resource>
         <directory>src/main/resources</directory>
         <includes>
           <include>**/*.properties</include>
           <include>**/*.xml</include>
         </includes>
          <filtering>false</filtering>
     </resource>

    </resources>
</build>

4.构建SqlSessionFactory。

从xml中创建SqlSessionFactory.

// 1. 解析扫码 mybatis.xml 文件
InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
// 2. 获取sqlsession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 3. 获得 sqlsession 对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 4. 执行sql语句
List<Student> students = sqlSession.selectList("com.beiyou.dao.StudentDao.selectAll");
// 打印结果
System.out.println(students);

是否弥补了JDBC的不足?

二、MyBatis 配置细节

2.1 log4j的使用

  1. 加入依赖

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

  1. 配置文件 log4j.properties

#定义全局日志级别调试阶段推荐debug
log4j.rootLogger = error,stdout
#包级别日志
log4j.logger.test.a = debug

### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.SimpleLayout

### 输出日志到文件=/logs/log.log ###
log4j.appender.logfile = org.apache.log4j.DailyRollingFileAppender
log4j.appender.logfile.File = /logs/log.log
log4j.appender.logfile.layout = org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

2.2 事务配置

transactionManager.type

JDBC : 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。

MANAGED : 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期。

2.3 连接池配置

dataSource.type

UNPOOLED : 这个数据源的实现会每次请求时打开和关闭连接.

POOLED : 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求。

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

2.4 映射文件的加载方式

1.resource: 使用相对于类路径的资源引用。

 <mapper resource="AuthorMapper.xml"/>

2.url: 使用完全限定资源定位符(URL)

 <mapper url="file:///D:/207/mybatis/src/main/resources/mapper/BlogMapper.xml"/>

3.class : 使用映射器接口实现类的完全限定类名

 <mapper class="org.mybatis.builder.BlogMapper"/>

4.name : 将包内的映射器接口实现全部注册为映射器

<mappers>
  <package name="com.beuyou.dao"/>
</mappers>

2.5 实体类别名处理

<typeAliases>
    <!--给单个类起别名。 type:类型 alias:别名-->
    <typeAlias type="com.beiyou.entity.Student" alias="student"></typeAlias>
    <!--给指定包下所有类起别名。 别名=类名(不区分大小写)-->
    <package name="com.beuyou.entity"/>
</typeAliases>

常见的 Java 类型内建的类型别名。它们都是不区分大小写的

别名

映射的类型

_byte

byte

_long

long

_short

short

_int

int

_integer

int

_double

double

_float

float

_boolean

boolean

string

String

byte

Byte

long

Long

short

Short

int

Integer

integer

Integer

double

Double

float

Float

boolean

Boolean

date

Date

decimal

BigDecimal

bigdecimal

BigDecimal

object

Object

map

Map

hashmap

HashMap

list

List

arraylist

ArrayList

collection

Collection

iterator

Iterator

2.6 外部属性配置文件存储数据库信息

  1. 配置db.properties数据库信息

driver=com.mysql.cj.jdbc.Driver
url=mysql://rm-bp169j3q9n43kxauzco.mysql.rds.aliyuncs.com:3306?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username=root123
password=Root_123

<properties resource="db.properties"></properties>
 <dataSource type="POOLED">
       <property name="driver" value="${driver}"/>
       <property name="url" value="${url}"/>
       <property name="username" value="${username}"/>
       <property name="password" value="${password}"/>
 </dataSource>

三、Mapper文件配置

3.1 常用属性

3.2 SQL 定义标签

1. select

用于数据查询操作,例:

<select id="selectUserInfo" parameterType="int" resultType="map">
  select * from user_info where id=#{keyId}
</select>

2. insert

用于数据保存操作,例:

<insert id="insertUserInfo" parameterType="map" useGeneratedKeys="true" keyProperty="keyId">
  insert into user_info (
	userName,
	userSex
  )values(
  	#{userName},
  	#{userSex}
  )
</insert>

PS:keyProperty属性可返回此条插入数据的主键值

3. update

用于数据更新操作,例:

<update id="updateUserInfo" parameterType="map">
  update  user_info
  set userName=#{userName}
  where id=#{keyId}
</update>

4. delete

用于数据删除操作,例:

<delete id="selectUserInfo" parameterType="int">
  delete  from user_info 
  where id=#{keyId}
</delete>

5. resultMap

SQL返回与实体类映射关系信息,例

<resultMap id="userInfoMap" type="User">
  <result property="user_name" column="userName"/>
  <result property="user_sex" column="userSex"/>
</resultMap>

<select id="selectUserInfo" parameterType="int" resultType="userInfoMap">
  select
  userName,
  userSex
  from user_info 
  where id=#{keyId}
</select>

将数据表字段userName、userSex映射到实体类User的user_name、user_sex

6. sql

用于定义可重用的 SQL 代码片段,以便在多个SQL语句中使用。 参数可以静态地(在加载的时候)确定下来,并且可以在不同的 include 元素中定义不同的参数值。例:

<!-- 定义 -->
<sql id="userColumns"> ${alias}.userName,${alias}.userSex</sql>

<!-- 运用 -->
<select id="selectUserInfo" resultType="map">
  select
    <include refid="userColumns"><property name="alias" value="t1"/></include>,
    <include refid="userColumns"><property name="alias" value="t2"/></include>
  from user_info  t1
  left join user_info_copy t2
</select>

3.3、SQL动态标签

1. if

单个条件判断,用以实现条件筛选,例:

<select id="selectUserInfo" parameterType="map" resultType="map">
  select * from user_info 
  where 1=1
  <if test="userSex !=null and userSex !='' ">
  	and userSex=#{userSex}
  </if>
  <if test="userName !=null and userName !='' ">
  	and userName like CONCAT('%',#{userName},'%')
  </if>
</select>

2. foreach

用于更新或保存数据时的批量操作,例:

<!-- userList为List<HashMap<String,Object>>类型数据 -->
insert into user_info(
userName,
userSex
)values
<foreach item="item" index="index" collection="userList" separator="," >
(
#{item.userName},
#{item.userSex}
)
</foreach>

<!-- userList为List<String>类型数据 -->
insert into user_info(
userName
)values
<foreach item="item" index="index" collection="userList" separator="," >
(
#{userName}
)
</foreach>

update user_info
set userAge=#{userAge}
where id in
<foreach collection="keyIds" index="index" item="item" separator="," open="(" close=")">
#{item}
</foreach>

3. choose/when/otherwise

用以实现条件的多种判断,类似与if else,例:

<select id="selectUserInfo" parameterType="map" resultType="map">
  select * from user_info 
  where 1=1
  <choose>
  	<when test="userFlag!=null and userFlag!='' and userFlag=='Y'">
  		and id<=100
  	</when>
  	<when test="userFlag!=null and userFlag!='' and userFlag=='N'">
  		and id <=200
  	</when>
  	<otherwise>
  		and id<=300
  	</otherwise>
  </choose>
</select>

4. where

只会在子元素返回任何内容的情况下才插入 “WHERE” 子句,并且可以自动处理判断条件语句返回的第一个and或or,例:

不使用where标签时,若userSex为空,语法错误会报错:

<select id="selectUserInfo" parameterType="map" resultType="map">
  select * from user_info 
  where
  <if test="userSex !=null and userSex !='' ">
  	userSex=#{userSex}
  </if>
  <if test="userName !=null and userName !='' ">
  	and userName like CONCAT('%',#{userName},'%')
  </if>
</select>

修改为:

<select id="selectUserInfo" parameterType="map" resultType="map">
  select * from user_info
  <where>
  <if test="userSex !=null and userSex !='' ">
  	userSex=#{userSex}
  </if>
  <if test="userName !=null and userName !='' ">
  	and userName like CONCAT('%',#{userName},'%')
  </if>
  </where>
</select>
自动转换为:select * from user_info where userName like ……

5. set

可以动态更新需要更新的列,忽略其它不更新的列,例:

<update id="updateUserInfo" parameterType="map">
  update  user_info
  <set>
  <if test="userName!= null and userName!=''">
  userName=#{userName},
  </if>
  userSex=#{userSex}
  </set>
  where id=#{keyId}
</update>

四、基于MyBatis的CURD操作

使用单元测试验证

  <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-api</artifactId>
      <version>5.6.0</version>
      <scope>test</scope>
    </dependency>

4.1 MyBatis查询的三种方式

  1. 返回单个对象 selectOne

  2. 返回对象List集合 selectList

  3. 返回对象Map集合 selectMap

<select id="selectOne" resultType="student">
   select *  from student where id=1
</select>
<select id="selectAll" resultType="student"  >
   select * from student
</select>
<select id="selectMap" resultType="map">
   select *  from student
</select>

4.2 MyBatis参数传递的三种方式

4.2.1 三种传参

  1. 传递的是基本类型+String ,使用 param1

  2. 传递类型是对象,接受使用对象的 属性名

  3. 传递的是map集合,接受时候使用map中的 key

<!-- 方法 Student selectOne(int id)-->
<!--param1:-->
<select id="selectOne" resultType="student" parameterType="int">
    select *  from student where id = #{id}
</select>
<!-- 方法 Student selectOne(StudentQuery query)-->
<!--#{} 里面放的是对象属性-->
<select id="selectOne2" resultType="student">
    select *  from student where id = #{id} and name = #{name}
</select>
<!-- 方法 Student selectOne(Map map)-->
<!--#{} 里面放的是map的key-->
<select id="selectOne3" resultType="student">
    select *  from student where id = #{a} and name = #{b}
</select>

// 【A】. 传递基本类型
 Student student = sqlSession.selectOne("test.c.selectOne", 2);
 // 打印
 System.out.println(student);
 // 【B】. 传递对象
 StudentQuery query = new StudentQuery();
 query.setId(2);
 query.setName("周星星");
 Student student = sqlSession.selectOne("test.c.selectOne2", query);
 //打印
 System.out.println(student);
 //【C】. 传递Map集合
 //id,name 一块封装到map集合
 Map<String,Object> map = new HashMap<>();
 map.put("a",2);
 map.put("b","周星星");
 Student student = sqlSession.selectOne("test.c.selectOne3", map);
 //打印
 System.out.println(student);

4.2.2 #和$区别:面试题

#:底层相当于占位符?

$:底层相当于字符串拼接

  1. 两者相比,占位符的方式更加方便,可以有效的防止SQL注入。

  2. 预编译

4.2.3 模糊查询

<!-- 模糊查询 -->
<select id="selectOne4" resultType="student">
     Student student = sqlSession.selectOne("test.c.selectOne4", "%敏%");
     select *  from student where  name like #{param1}
     Student student = sqlSession.selectOne("test.c.selectOne4", "敏");
     select *  from student where name like concat('%',#{param1},'%')
</select>

4.2.4 Model对象字段名称与数据库不一致,使用resultMap指定

 <select id="selectlike2" resultMap="usermap" >
        select *  from user where email like concat('%',#{param1},'%')
    </select>

    <resultMap id="usermap" type="User">

        <!--
            主键映射  使用id标签
            propetry java中的类型名称
            column  数据库中的字段名
        -->
        <id property="pwd" column="password"/>

    </resultMap>

XML

4.2.5 include标签

1、首先定义一个sql标签,一定要定义唯一id。    <sql id="columns">
        id, title ,brief
    </sql>
2、然后通过id引用 <select id="selectOne"  resultMap="productResultMap1" >
        select
        <include refid="columns"/>
        from product where id = 8
 </select>

XML

4.3 MyBatis完整DML全部操作

DML与DDL的含义:

1、DML(Data Manipulation Language)数据操作语言-数据库的基本操作,SQL中处理数据等操作统称为数据操纵语言,简而言之就是实现了基本的“增删改查”操作。包括的关键字有:select、update、delete、insert、merge

2、DDL(Data Definition Language)数据定义语言-用于定义和管理 SQL 数据库中的所有对象的语言,对数据库中的某些对象(例如,database,table)进行管理。包括的关键字有:

create、alter、drop、truncate、comment、grant、revoke

4.3.1 CUD

【1】新增

<!-- 方法 int insert(Student student)-->
<insert id="insert">
    insert into student (name,age) values (#{name},#{age})
</insert>

Student student = new Student();
student.setName("邓超");
student.setAge(38);
int rowNum  = sqlSession.insert("com.beiyou.dao.StudentMapper.insert", student);
//MyBatis 默认不自动提交事务,所以 增删改功能 需要我们手动提交事务
sqlSession.commit();

【2】修改

<!-- 传统方法 int update(Student student)-->
<update id="update">
    update student set name = #{name},age = #{age} where id = #{id}
</update>

Student student = new Student();
student.setName("邓超111");
student.setAge(380);
student.setId(6);
int rowNum  = sqlSession.update("com.beiyou.dao.StudentMapper.update", student);
//MyBatis 默认不自动提交事务,所以 增删改功能 需要我们手动提交事务
sqlSession.commit();

【3】删除

<!-- 传统方法 int delete(int id)-->
<delete id="delete">
    delete from student  where id = #{param1}
</delete>

int rowNum  = sqlSession.delete("test.d.delete", 6);
//MyBatis 默认不自动提交事务,所以 增删改功能 需要我们手动提交事务
sqlSession.commit();

4.3.2 设置SqlSession提交

MyBatis 默认不自动提交事务,所以 增删改功能 需要我们手动提交事

【1】SqlSession sqlSession = factory.openSession(true);

【2】sqlSession.commit();

4.4 扩展

4.4.1 接口编程

package com.beiyou.dao;

public interface UserDao {

    List<User> selectAll();
}

<mapper namespace="com.beiyou.dao.UserDao">

 <select id="selectAll" resultType="user" >
     select  *  from 202_user
 </select>

</mapper>

  
  UserDao mapper = sqlSession.getMapper(UserDao.class);
  mapper.selectAll();

4.4.2通过表达式,实现多场景多条件组合查询

<select id="select" resultMap="productResultMap1">
        select id, categoryId,title ,brief from 202_product
        <where>
            <if test="id != null">
                and  id = #{id}
            </if>
            <if test="ids != null">
                and id in
                <foreach collection="ids" item="item"  open="(" close=")" separator=",">
                    #{item}
                </foreach>
            </if>
            <if test="categoryId != null">
                and  categoryId= #{categoryId}
            </if>
            <if test="categoryIds != null">
                and categoryId in
                <foreach collection="categoryIds" item="item" open="(" close=")" separator=",">
                    #{item}
                </foreach>
            </if>
            <if test="name != null">
                and title like concat('%',#{name},'%')
            </if>
        </where>

    </select>

    @Test
    public void selectQuery() throws IOException {
        ProductDao productDao = sqlSession.getMapper(ProductDao.class);
        ProductQuery query = new ProductQuery();
        //query.setId(40);
        //query.setCategoryId(1);
        //query.setName("梨38");
        //query.setIds(new Integer[]{38,42,50,51,52});
        query.setCategoryIds(new Integer[]{3});
        List<Product> products = productDao.select(query);
        System.out.println(products);
    }

4.4.3 注解

 <mapper class="com.beiyou.dao.UserDao"/>

public interface UserDao {

    @Select("select *  from  202_user limit 1")
    User select();  //insert into order_item (productId,productName,productImg,price,qty,orderId)  values (1,2,3),(2,3,4).....
    @Insert("<script> " +
            "insert into "  +
            " order_item (productId,productName,productImg,price,qty,orderId) " +
            "values " +
            "<foreach collection='items'  item='item' separator=','> "+
            "(#{item.productId},#{item.productName},#{item.productImg},#{item.price},#{item.qty},#{item.orderId})"+
            "</foreach> </script>" )
      int insertAll(List<OrderItemEntity> items);


    @Select("<script> " +
            "select *  from  order_item where 1 = 1 "  +
            "<if test='id != null'>" +
            " and id = #{id} "+
            "</if> "+
            "<if test='orderId != null'>" +
            " and orderId = #{orderId} "+
            "</if> "+
            "<if test='orderIds != null'>" +
            " and orderId in  "+
            "<foreach collection='orderIds' open='(' close=')'  item='item' separator=','> "+
            "#{item}"+
            "</foreach> "+
            "</if> "+
           "</script>" )@Results(id="studentMap",value={    @Result(column=“id”, property=“id”, jdbcType=JdbcType.INTEGER, id=true),    @Result(column=“name”, property=“name”, jdbcType=JdbcType.VARCHAR),    @Result(column=“class_id”, property=“classId”, jdbcType=JdbcType.INTEGER)})

    List<OrderItemEntity> select(OrderItemQueryDto queryDto);


}

4.4.4 SelecKey标签使用

Mybatis之useGeneratedKeys和selectKey的基本用法与区别_mybatis selectkey usegeneratedkeys_poppyCL的博客-CSDN博客

一、useGeneratedKeys数据库本身具备主键自动增长的功能,才能使用useGeneratedKeysoracle不支持true<insert id="insert" useGeneratedKeys="true" keyProperty="idColName"> insert into tableName (colName) values (#{colVal,jdbc..._mybatis selectkey usegeneratedkeys

https://blog.csdn.net/poppyCL/article/details/103347385

   <insert id="insert"  parameterType="UserEntity">

        insert user (email,password) values (#{email},#{pwd})

        <selectKey keyProperty="id" resultType="integer" keyColumn="newId" order="AFTER">
            SELECT LAST_INSERT_ID() as newId
        </selectKey>
    </insert>

<selectKey resultType="integer" keyColumn="newId" keyProperty="id" order="BEFORE">

              SELECT (max(id)+1) as newId from  205_category
</selectKey>

注解版

@SelectKey(statement="SELECT last_insert_id", keyProperty="id", before=false, resultType=Long.class)

五 MyBatis 高级关系查询

  • 一个会员只属于一个详情 ==> 会员对详情表是一对一关系

  • 不管是一对一还是多对多,都要使用<resultMap> ,属性有id 和type

  • 一对一中,<resultMap>内要用<association>来映射复杂对象,属性有 :

  •   (property和javaType) ==> 嵌套结果

  •   (property, column, select) ==> 嵌套查询

  • 一对多中,<resultMap>内要用<collection>来映射复杂对象,属性有property和ofType

  • 注意防范<resultMap>和<association>或<collection>中字段名冲突的问题!

5.1 一对一

<resultMap> <association>

<association> 元素,通常可以配置一下属性

- propery:指定映射到实体类对象属性,与表字段一一对应

- column:指定表中对应的字段

- javaType:指定映射到实体对象属性的类型

- select:指定引入嵌套查询的子SQL语句,该属性用于关联映射中的嵌套查询

- fetchType:指定在关联查询时是否启用延迟加载。FetchType属性有lazy和eager(实时)两个属性值,默认值为lazy

默认为lazy(默认关联映射延迟加载)

create table 202_user(    id int unsigned auto_increment,    tel varchar(50) not null,    password varchar(32) not null,    primary key(id));
CREATE TABLE `202_userinfo` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '唯一标识',
  `name` varchar(100) NOT NULL COMMENT '姓名',
  `sex` varchar(100) DEFAULT NULL COMMENT '性别',
  PRIMARY KEY (`id`)
)

实体对象

@Data public class User {    private Integer id;    private String tel;    private String password;    private UserInfo userinfo;}public class UserInfo {    private Integer id;    private String name;    private String sex;   private Integer age;
}

UserMapper.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.beiyou.dao.UserDao2">

    <resultMap id="usermap" type="com.beiyou.model.User">
        <id property="id" column="id"/>
        <result property="tel" column="tel"/>
        <result column="password" property="password"/>
        <association property="userInfo" javaType="com.beiyou.model.UserInfo">
            <id property="id" column="id"/>
            <result property="name" column="name"/>
            <result property="sex" column="sex"/>
        </association>
    </resultMap>


    <select id="one2one" resultMap="usermap" >
        select *
        from `202_user`   u
        left join `202_userinfo`  ui
        on u.id = ui.userId
    </select>

   <resultMap id="userMap" type="com.beiyou.model.User">
    <id column="id" property="id"/>
    <result column="tel" property="tel"/>
    <result column="password" property="password"/>
    <association property="userInfo" column="Id"  fetchType="lazy" javaType="com.beiyou.model.UserInfo"
     select="selectUserinfo">
        <id property="id" column="id"/>   bug 必须书写
        <result property="name" column="name"/>
        <result property="sex" column="sex"/>
    </association>
  
</resultMap>

    <select id="lazyone2one" resultMap="usermap2">
        select  *  from  202_user
    </select>

    <select id="selectName" resultType="com.beiyou.model.UserInfo">
        select * from 202_userinfo where userId = #{id}
    </select>
</mapper>

UserDao.java

public interface UserDao {
     User one2one(String name);
     User lazyone2one(String name);
}

5.2 一对多

<resultMap> <collection>

CREATE TABLE `202_address` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '唯一id',
  `userId` int NOT NULL COMMENT '用户编号',
  `province` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '省',
  `city` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '市',
  `address` varchar(100) DEFAULT NULL COMMENT '详细地址',
  PRIMARY KEY (`id`)
)


<resultMap id="userMap" type="com.beiyou.model.User">
    <id column="id" property="id"/>
    <result column="tel" property="tel"/>
    <result column="password" property="password"/>
    <association property="userInfo" column="Id"  fetchType="lazy" javaType="com.beiyou.model.UserInfo"
     select="selectUserinfo">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="sex" column="sex"/>
    </association>
    <collection property="addresses" column="id" fetchType="lazy" javaType="java.util.ArrayList"
           ofType="com.beiyou.model.Address"  select="selectAddress" >
        <id property="id" column="id"/>
        <result property="province" column="province"/>
        <result property="city" column="city"/>
        <result property="county" column="county"/>
        <result property="address" column="address"/>
    </collection>
</resultMap>
     <select id="selectAddr" resultType="com.beiyou.model.Address">
        select * from 202_address where userId = #{userId}
    </select>


使用Mapper注解,实现一对一和一对多关系查询


    @Results(id="userMap", value = {
            @Result(column = "id", property = "id", id = true),
            @Result(column = "tel", property = "tel"),
            @Result(column = "password", property = "password"),
            @Result(property = "userInfo", column = "id",
                    one = @One(select = "selectUserinfo",fetchType = FetchType.LAZY)), 可以不用写具体映射,但是用xml的时候,必须写
            @Result(column = "id",  property = "addresses" ,
                    many = @Many(select = "selectAddress",fetchType = FetchType.LAZY))
    })

}
    @Select("select  *  from 202_user  u   where u.id = #{id}")
    List<User> layeOne2One(int id);



     @Select("select  *  from 202_address where userId = #{id}")
    List<Address> selectAddress(Integer id);

测试代码

   @Test
    public void test(){
        UserMapper2 dao = sqlSession.getMapper(UserMapper2.class);
        List<User> users = dao.queryUserAll();

    }

Java

六 MyBatis缓存机制

mybatis.xml

   <settings>
        <setting name="cacheEnabled" value="true"/> //开启全局的二级缓存
    </settings>

//清空缓存数据
       @Options(flushCache = Options.FlushCachePolicy.TRUE)
 
       @Select(" select *  from  202_user where id= 46")
       User  one();

6.1 一级缓存

一级缓存作用域是sqlsession级别的,同一个sqlsession中执行相同的sql查询(相同的sql和参数),第一次会去查询数据库并写到缓存中,第二次从一级缓存中取。

一级缓存是基于 PerpetualCache 的 HashMap 本地缓存,默认打开一级缓存。

6.1.1何时清空一级缓存

如果中间sqlSession去执行commit操作(执行插入、更新、删除),则会清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。

一级缓存时执行commit,close,增删改等操作,就会清空当前的一级缓存;当对SqlSession执行更新操作(update、delete、insert)后并执行commit时,不仅清空其自身的一级缓存(执行更新操作的效果),也清空二级缓存(执行commit()的效果)。

6.1.2一级缓存无过期时间,只有生命周期

MyBatis在开启一个数据库会话时,会创建一个新的SqlSession对象,SqlSession对象中会有一个Executor对象,Executor对象中持有一个PerpetualCache对象。当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。

6.2 二级缓存

它指的是Mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。

同一个工厂生产的sqlsession,批次号相同.

二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。

6.2.1 二级缓存何时存入

在关闭sqlsession后(close或commit),才会把该sqlsession一级缓存中的数据添加到namespace的二级缓存中。

开启了二级缓存后,还需要将要缓存的pojo实现Serializable接口,为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一定只存在内存中,有可能存在硬盘中

6.2.2二级缓存有过期时间

每当存取数据的时候,都有检测一下cache的生命时间,默认是1小时,如果这个cache存活了一个小时,那么将整个清空一下.

6.2.3 执行流程

当 Mybatis 调用 Dao 层查询数据库时,先查询二级缓存,二级缓存中无对应数据,再去查询一级缓存,一级缓存中也没有,最后去数据库查找。


       SqlSessionFactory级别缓存,会话工厂级别
        SqlSession s1 = sf.openSession();
        SqlSession s2 = sf.openSession();
        SqlSession s3 = sf.openSession();
        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s3);
    开发者必须自己配置二级缓存
    二级缓存是人工开启的,需要在XxxxMapper.xml 文件中加入如下开启
       方法一
            <cache eviction="FIFO" flushInterval="60000" size="5120" readOnly="true" />
            <select id="queryAll" resultType="book" useCache="false">  默认使用缓存,填写false此操作不让缓存
            select * from book
            </select>

       方法二
            @CacheNamespace(eviction = FifoCache.class, flushInterval = 60000, size = 1024, readWrite = true)
            public interface BookMapper {
                @Select("select * from book") 
                @Options(useCache = true)
                public List<Book> queryAll();

                @Select("select * from book where id = #{id}")
                public Book queryById(int id);
            }           

    注意:使用缓存时,最好给实体类序列化。

Java

Student.java

@Data
public class Student implements Serializable {
    private int id;
    private String name;
    private int age;
    private double money;
    private String info;
}

Plain Text

StudentMapper.java

@CacheNamespace 
public interface StudentMapper {
    @Select("select * from t_student")
    @Options(useCache = true) //开启或关闭二级缓存
    public List<Student> page();

    @Select("select * from t_student where id = #{id}")
   @Options(useCache = true)
    public Student queryById(int id);
}

Java

@Test
public void t5() {
    var session = sf.openSession();
    var sm = session.getMapper(StudentMapper.class);
    System.out.println(sm.page());
    System.out.println(sm.page());
    System.out.println(sm.page());
    System.out.println(sm.page());

    System.out.println("---------------------------");
    System.out.println(sm.queryById(5));
    session.commit();//将当前会话的查询,保存到二级缓存中,
    System.out.println(sm.queryById(5));
    System.out.println(sm.queryById(5));
    System.out.println(sm.queryById(5));

    System.out.println("----------------------");
    var s2 = sf.openSession();
    var sm2 = s2.getMapper(StudentMapper.class);
    System.out.println(sm2.queryById(5));
}

Plain Text

六 常见问题

1.MySQL连接数据库时,添加语句:“allowMultiQueries=true”的作用:

  1. 可以在sql语句后携带分号,实现多语句执行。

  2. 可以执行批处理,同时发出多个SQL语句。

2.找不到配置文件

  • 25
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

这孩子叫逆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值