Mybatis

Mybatis

持久化

数据持久化

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

持久层

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

第一个mybatis程序

  • 导入依赖
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.11</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>3.5.6</version>
</dependency>
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>8.0.29</version>
</dependency>
  • 编写mybatis工具类
package com.fiee.utlis;

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 MybatisUtlis {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            //使用mybatis第一步获取sqlSessionFactory对象
            String resource = "org/mybatis/example/mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //既然有了sqlSessionFactory,顾名思义,我们就可以获得sqlsession的实例了
    //sqlsession完全包含了面向数据库执行sql命令所需的所有方法
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();

    }
}

编写代码

  • 实体类

    package com.fiee.pojo;
    //实体类
    public class Account {
        private int id;
        private String name;
        private double money;
    
        public Account() {
        }
    
        public Account(int id, String name, double money) {
            this.id = id;
            this.name = name;
            this.money = money;
        }
    
        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 double getMoney() {
            return money;
        }
    
        public void setMoney(double money) {
            this.money = money;
        }
    
        @Override
        public String toString() {
            return "Account{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", money=" + money +
                    '}';
        }
    }
    
  • Dao类

  • package com.fiee.dao;
    
    import com.fiee.pojo.Account;
    
    import java.util.List;
    
    public interface AccountDao {
        List<Account> getAccountList();
    }
    
  • 接口实现类,由原来接口实现类转变为一个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.fiee.dao.AccountDao">
<!--    id对应原来的方法名字 resultType 是接口约为实现接口类-->
    <select id="getAccountList" resultType="com.fiee.pojo.Account">
        select * from account
    </select>
</mapper>

测试

package com.fiee;

import com.fiee.dao.AccountDao;
import com.fiee.pojo.Account;
import com.fiee.utlis.MybatisUtlis;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class TestDao {
    @Test
    public void test(){
        //获得sqlsession对象
        SqlSession sqlSession = MybatisUtlis.getSqlSession();
        //执行SQL
        AccountDao mapper = sqlSession.getMapper(AccountDao.class);
        List<Account> accountList = mapper.getAccountList();
        for (Account account:accountList) {
            System.out.println(account);
        }
        //关闭sqlsession
        sqlSession.close();
    }
}

Map

传递Map中的key

Map传递参数,直接在sql中取出key即可[parameterType="map"]

对象传递参数,直接在sql中取对象的属性即可!

只有一个基本类型参数的情况下,可以直接在sql中取到!

多个参数用Map,或者注解

配置解析

1.核心配置文件

  • mybatis-config.xml

  • MyBatis的配置文件包含了会深深影响MyBatis行为的设置和属性信息

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

配置环境(environments)

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

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

学会适应配置多套运行环境

Mybatis默认的事务管理器就是JDBC,连接池:POOLED

属性(properties)

我们可以通过properties属性来实现引用配置文件

这些属性都是可外部配置且动态替换的,既可以在典型的java属性文件中配置,亦可以通过properties元素的子元素来传递(db.properties)

db.properties

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

在核心配置文件中映入

<properties resource="db.properties">
    <property name="" value=""/>
</properties>
  • 可以直接引入外部文件
  • 可以在其中增加一些属性配置
  • 如果两个文件有同一个字段,优先使用外部配置文件的

类型别名(typeAliases)

  • 类型别名可为 Java 类型设置一个缩写名字。
  • 意在降低冗余的全限定类名书写
<!--    可以给实体类取别名-->
    <typeAliases>
        <typeAlias type="com.fiee.pojo.Account" alias="Account"/>
    </typeAliases>
  • 也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,

    • 扫描实体类的包,它的默认别名就为这个类的首字母小写的类名
  • 在实体类上使用注解命名@Alias("")

  • <typeAliases>
        <package name="com.fiee.pojo"/>
    </typeAliases>
    

在实体类比较少的时候使用第一种

实体类十分多,使用第二种

第一种可以diy别名,第二种不行(但可以在注解取@Alias(""))

设置

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

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

映射器(mappers)

MapperRegistry:注册绑定我们的Mapper文件;

方式一:

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

方式二:

<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
</mappers>

注意点:

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

方式三:

<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>

注意点:

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

生命周期和作用域

作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题

SqlSessionFactoryBuilder

  • 一旦创建了 SqlSessionFactory,就不再需要它了。
  • 局部变量

SqlSessionFactory

  • 说白了就是可以想象为:数据库连接词
  • SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
  • 因此 SqlSessionFactory 的最佳作用域是应用作用域。
  • 最简单的就是使用单例模式或者静态单例模式。

SqlSession

  • 连接到连接池的一个请求!
  • 用完关闭,否则资源被占用!

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

resultMap

结果集映射

<!--    结果集映射-->
    <resultMap id="AccountMap" type="Account">
<!--        coulumn数据库中的字段,property实体类中的属性-->
        <result column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="money" property="money"/>
    </resultMap>
<select id="getAccountList" resultMap="AccountMap">//这个跟上面id一样
        select * from account
    </select>
  • resultMap元素是Mybatis中最强大的元素

  • ResultMap的设计是想是,对于简单的语句根本不需要配置显示的结果集映射,而复杂一点的语句只需要描述他们的关系就行了

  • ResultMap 的优秀之处——你完全可以不用显式地配置它们

  • 需要映射谁就写谁就好了

日志

日志工厂

如果一个数据库操作,出现了异常,我们需要排错。日志就是最好的助手!

曾经:sout,debug

现在:日志工厂

logImpl 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING 未设置

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

Log4j

什么是Log4j

  • 可以通过控制日志信息输送的目的地是控制台,文件,GUI组件
  • 我们也可以控制每一条日志的输出格式
  • 通过定义每一条日志信息的级别,我们能够更加细致的控制日志的生成过程
  • 通过一个配置文件来灵活地配置,而不需要修改应用代码

1.先导入log4j的包

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

后面要用百度配置

简单使用

  1. 在要使用log4j的类中,导入包import org.apache.log4j.Logger

  2. 在日志对象,参数为当前类的class

    static Logger logger=Logger.getLogger(UserDaoTest.class)
    
  3. 日志级别

    logger.info("info:进入了testLog4j");
    logger.debug("debug:进入了testLog4j");
    logger.error("error:进入了testLog4j");
    

分页

  • 减少数据的处理量

使用mybatis实现分页,核心SQL

  1. 接口
  2. Mapper.xml
  3. 测试

注解开发

  1. 注解在接口上实现

  2. @select("select * from user")
    List<User> getUsers();
    
  3. 需要在核心配置文件中绑定接口!

  4. <绑定接口>
    <mappers>
    	<mapper class="com.xx.xx.xx"/>
    </mappers>
    
  5. 测试

Lombok

使用步骤:

  1. 在idea中安装Lombok插件
  2. 在项目中导入lombok的jar包(maven)
  3. 在实体类上加上注解即可(data)

多对一

使用结果集映射

复杂的属性,我们需要单独处理

对象:association

集合:collection

 <resultMap id="AccountMap" type="Account">
<!--        coulumn数据库中的字段,property实体类中的属性-->
        <result column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="money" property="money"/>
        <collection property="money" column="s" javaType="传入表的类型" select="嵌套查询,联合的表id"
    </resultMap>
    <select id="getAccountList" resultMap="AccountMap">
        select * from account
    </select>

注:

​ javaType指定属性的类型

​ 集合中的泛型信息,我们使用ofType获取

动态SQL

什么是动态SQL:动态SQL就是指根据不同的条件生成不同的SQL语句

if -where标签

接口方法 查询员工 根据不同的条件来判断

    /**
     * 动态sql if where 标签 根据传入参数不同动态判断条件
     */
    Employee selectDByEmp(Employee employee);
<select id="selectDByEmp" resultType="com.yu.pojo.Employee">
    select id,last_name,email,salary
    from tbl_employee
    <where>
        <if test="id != null">
            and id=#{id}
        </if>
        <if test="lastName != null ">
            and last_name=#{lastName}
        </if>
        <if test="email != null">
            and email=#{email}
        </if>
        <if test="salary != null">
            and salary=#{salary}
        </if>
    </where>
</select>

choose标签

/**
 * 动态sql choose 标签 单条件查询 有一个条件满足就只接受一个条件 即使有多个条件满足 也无法加入进来
 * 相当于 if-else 或者 switch-case
 */
Employee selectDByChoose(Employee employee);
<select id="selectDByChoose" resultType="com.yu.pojo.Employee">
    select id,last_name,email,salary
    from tbl_employee
    <where>
        <choose>
            <when test="id != null">
                id=#{id}
            </when>
            <when test="lastName != null">
                last_name=#{lastName}
            </when>
            <when test="email != null and">
                email=#{email}
            </when>
            <when test="salary != null and">
                salary=#{salary}
            </when>
            <otherwise>
                1=1
            </otherwise>
        </choose>
    </where>
</select>

set标签

set标签 解决语句上的逗号问题 注意写在where前面

</insert>
<update id="update">
    update tbl_employee
    <set>
        <if test="lastName != null ">
            last_name=#{lastName},
        </if>
        <if test="email != null ">
            email=#{email},
        </if>
        <if test="salary != null ">
            salary=#{salary},
        </if>
    </set>
    where
    id=#{id}
</update>

Sql片段

有时候,我们可能会将一些功能的部分抽取出来,方便复用!

  1. 使用SQL标签抽取公共部分
  2. 在需要使用的地方使用include标签引用即可

注意事项:

  • 最好基于单表来定义SQL片段!
  • 不要存where标签
  • 尽量只存if判断就可以了
id, user_ name,password, name , age, sex, birthday , created , updated
<select id= "queryAllUser" resultType= "User">
	select <include refid= "userColumn"></include> from tb_ user
</ select>

Foreach

<select id="selectPostIn" resultType="domain.blog.Post">
  SELECT *
  FROM POST P
  WHERE ID in
    //collection指定的集合, open是开头是什么 separator是拼接符 close是最后
  <foreach item="item" index="index" collection="list"
      open="(" separator="," close=")">
        #{item}
  </foreach>
</select>

二级缓存

步骤:

  1. 开启缓存

  2. <settings>
    	<setting name="cacheEnabled" value="true"/>
    </setting>
    
  3. 在当前Mapper.xml中使用二级缓存

  4. <cache/>

小结:

  • 只要开启了二级缓存,在同一个Mapper下就有效
  • 所有的数据都会先放在一级缓存中
  • 只有当会话提交,或者关闭的时候,才会提交到二级缓存中
posted @ 2022-06-11 19:37  fieeDream  阅读(18)  评论(0编辑  收藏  举报