Mybatis-9.28

回顾:

  • JDBC

  • MySQL

  • Java基础

  • maven

  • junit

SSM框架:配置文件。最好的方式:看官网;

1、简介

1.1、什么是mybatis?

如何获得mybatis

  • maven仓库

     <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
     <dependency>
         <groupId>org.mybatis</groupId>
         <artifactId>mybatis</artifactId>
         <version>3.5.6</version>
     </dependency>
     ​
  • Github

1.2、持久层

数据持久化

  • 持久化就是将程序的数据在持久状态和瞬时状态传化的过程。

  • 内存:断电即失

  • 数据库(JDBC),io文件持久化。

  • 生活:冷藏、罐头

为什么需要持久化?

  • 有一些对象不能让它丢掉

  • 内存太贵了

1.3、持久层

Dao层、Service层、Controller层......

  • 完成持久化工作的代码块

  • 层是界限十分明显。

1.4、为什么需要Mybatis

  • 方便

  • 传统的JDBC太复杂了。简化,框架。自动化

  • 帮助程序员将数据存入数据库中。

最重要的一点:用的人多

2、第一个mybatis程序

思路:搭建环境----->导入mybatis----->编写代码--->测试!

2.1、搭建环境

搭建数据库

新建项目

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

  2. 导入maven依赖

     <!--导入依赖-->
         <dependencies>
     <!--        mysql驱动-->
             <dependency>
                 <groupId>mysql</groupId>
                 <artifactId>mysql-connector-java</artifactId>
                 <version>5.1.47</version>
             </dependency>
     ​
     <!--        mybatis-->
             <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
             <dependency>
                 <groupId>org.mybatis</groupId>
                 <artifactId>mybatis</artifactId>
                 <version>3.5.6</version>
             </dependency>
     ​
     <!--        junit-->
             <dependency>
                 <groupId>junit</groupId>
                 <artifactId>junit</artifactId>
                 <version>4.12</version>
                 <scope>test</scope>
             </dependency>
         </dependencies>

2.2、创建一个模块

  • 编写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核心配置文件-->
     <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;charcterEncoding=UTF-8"/>
                     <property name="username" value="root"/>
                     <property name="password" value="root"/>
                 </dataSource>
             </environment>
         </environments>
     </configuration>
  • 编写mybatis工具类

     ​
     //sqlSessionFactory-------->sqlSession
     public class mybatisUtil {
         
         private static SqlSessionFactory sqlSessionFactory;
         static {
     ​
             try {
                 //使用mybatis第一步:获取sqlSessionFactory对象
                 String resource = "mybatis-config.xml";
                 InputStream inputStream = Resources.getResourceAsStream(resource);
                 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
             } catch (IOException e) {
                 e.printStackTrace();
             }
         }
         //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。SqlSession 
         // 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。
         public static SqlSession getSqlSession(){
             return sqlSessionFactory.openSession();
            
         }
     ​
     }

2.3、编写代码

  • 实体类

     package com.hbx.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;
         }
     ​
         @Override
         public String toString() {
             return "User{" +
                     "id=" + id +
                     ", name='" + name + '\'' +
                     ", pwd='" + pwd + '\'' +
                     '}';
         }
     }
     ​

  • Dao接口

     public interface UserDao {
         List<User> getUserlist();
     }

  • 接口实现类由原来的UserDaoImpl转变为Mapper配置文件.

     <?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.hbx.dao.UserDao">
     <!--    select查询语句-->
         <select id="getUserlist" resultType="com.hbx.pojo.User">
             select * from mybatis.user;
         </select>
     </mapper>

2.4、测试

注意点:绑定异常

核心配置文件中注册mappers

  • junit测试

     public class UserDaoTest {
         @Test
         public void test(){
             //第一步:获得SQLsession对象
             SqlSession sqlSession = MybatisUtils.getSqlSession();
             //第二步:执行 方式一:getMapper(UserDao.class);
             UserDao userDao = sqlSession.getMapper(UserDao.class);
             List<User> userlist = userDao.getUserlist();
             for (User user : userlist) {
                 System.out.println(user);
             }
             //关闭sqlsession
             sqlSession.close();
         }
     }

3、CRGD(增删改需要提交事务)

1、namespace

2、select

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

3、insert

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

4、update

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

5、Delete

 <delete id="deleteUser" parameterType="int">
     delete
     from mybatis.user
     where id = #{id};
 </delete>

接口

 public interface UserDao {
     //获取全部用户
     List<User> getUserlist();
     //根据id查询用户
     User getUserById(int id);
     //insert一个用户
     int addUser(User user);
     //修改用户
     int updateUser(User user);
     //删除一个用户
     int deleteUser(int id);
 }

测试

 package com.hbx.dao;
 ​
 import com.hbx.pojo.User;
 import com.hbx.utils.MybatisUtils;
 import org.apache.ibatis.session.SqlSession;
 import org.junit.Test;
 ​
 import java.util.List;
 ​
 public class UserDaoTest {
     @Test
     public void test(){
         //第一步:获得SQLsession对象
         SqlSession sqlSession = MybatisUtils.getSqlSession();
         try {
             //第二步:执行 方式一:getMapper(UserDao.class);
             UserDao userDao = sqlSession.getMapper(UserDao.class);
             List<User> userlist = userDao.getUserlist();
 ​
 //        //方式二:不建议
 //        List<User> userlist = sqlSession.selectList("com.hbx.dao.UserDao.getUserlist");
             for (User user : userlist) {
                 System.out.println(user);
             }
         }catch (Exception e){
             e.printStackTrace();
         }finally {
             //关闭sqlsession
             sqlSession.close();
         }
     }
     @Test
     public void getUserById(){
         SqlSession sqlSession = MybatisUtils.getSqlSession();
 ​
 ​
         UserDao mapper = sqlSession.getMapper(UserDao.class);
         User user = mapper.getUserById(1);
         System.out.println(user);
 ​
 ​
         sqlSession.close();
     }
     //增删改需要提交事务
     @Test
     public void addUser(){
         SqlSession sqlSession = MybatisUtils.getSqlSession();
         UserDao mapper = sqlSession.getMapper(UserDao.class);
         int res = mapper.addUser(new User(4, "会话", "23256"));
         if (res>0){
             System.out.println("插入成功!");
         }
         //提交事务
         sqlSession.commit();
         sqlSession.close();
     }
     @Test
     public void updateUser(){
         SqlSession sqlSession = MybatisUtils.getSqlSession();
         UserDao mapper = sqlSession.getMapper(UserDao.class);
         mapper.updateUser(new User(4,"呜哈哈","001456"));
 ​
         sqlSession.commit();
         sqlSession.close();
     }
     @Test
     public void deleteUser(){
         SqlSession sqlSession = MybatisUtils.getSqlSession();
 ​
         UserDao mapper = sqlSession.getMapper(UserDao.class);
         mapper.deleteUser(4);
 ​
         sqlSession.commit();
         sqlSession.close();
     }
 ​
 }
 ​

6、分析错误

遇到的问题:

  1. 配置文件没有注册

  2. 绑定接口错误

  3. 方法名不对

  4. 返回类型不对

  5. maven导出资源

7、万能Map

假设我们的实体类,或者数据库中的表,字段或者参数过多,我们应当使用map!

//万能Map
int addUser2(Map<String,Object> map);
<!-- 传递map中的键-->
    <insert id="addUser2" parameterType="map">
        insert into mybatis.user (id,name,pwd) value (#{userId},#{userName},#{userpassword})
    </insert>
@Test
public void addUser2(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);

    HashMap<String, Object> HashMap = new HashMap<>();
    HashMap.put("userId",5);
    HashMap.put("userName","低调");
    HashMap.put("userpassword","0014555");
    mapper.addUser2(HashMap);
    sqlSession.commit();
    sqlSession.close();
}

map传递参数直接在SQL中取出key即可!

parameterType="map"

对象传递传输,直接在SQL中取对象的属性即可!

parameterType="Object"

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

parameterType="int/...." //可以不写 但不能为空

多个参数用map,或者注解

8、思考题

模糊查询怎么写?

  1. Java代码执行的时候,传递通配符%

    List<User> userList = mapper.getUserLike("%韩%");
  2. 在SQL拼接中使用通配符!

    select * from user where name like "%" #{value} "%"

4、配置解析

4.1、核心配置文件

  • mybatis-config.xml

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

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

4.2、环境配置(environments)

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

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

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

4.3、属性(properties)

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

这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。【db.properties】

编写一个配置文件db.properties

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

在核心配置文件中引入

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

  • 可以在其中增加一些属性配置

  • 如果两个文件有同一个字段,优先使用外部配置文件的!

4.4、类型别名(typeAliases)

  • 类型别名可为 Java 类型设置一个缩写名字

  • 它仅用于 XML 配置,意在降低冗余的全限定类名书写。

    <!-- 可以给实体类起别名-->
    <typeAliases>
      <typeAlias type="com.hbx.pojo.User" alias="User"/>
    </typeAliases>

    也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:

    扫描实体类的包,它的默认别名就为这个类的类名,首字母小写!

 <!-- 可以给实体类起别名-->
 <typeAliases>
     <package name="com.hbx.pojo" />
     <!--  <typeAlias type="com.hbx.pojo.User" alias="User"/>-->
 </typeAliases>

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

但是实体类非常多,建议使用第二种。

区别:第一种可以DIY别名,第二种不行,如果非要改,需要在实体类上增加注解。

 //实体类
 @Alias("User")

4.5、设置

4.6、其他配置

4.7、映射器(mappers)

MapperRegistry:注册mapper文件!

方式一:【推荐使用】

 <!--    每一个Mapper.xml都需要在mybatis核心配置文件中注册!-->
     <mappers>
         <mapper resource="com/hbx/dao/UserMapper.xml"/>
     </mappers>

方式二:使用class文件绑定注册!

     <mappers>
 <!--        <mapper resource="com/hbx/dao/UserMapper.xml"/>-->
         <mapper class="com.hbx.dao.UserMapper"/>
     </mappers>

注意点:

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

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

方式三:使用扫描包进行注入绑定

    <mappers>
<!--        <mapper resource="com/hbx/dao/UserMapper.xml"/>-->
<!--        <mapper class="com.hbx.dao.UserMapper"/>-->
        <package name="com.hbx.dao"/>
    </mappers>

4.8、生命周期和作用域

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

SqlSessionFactoryBulider:

  • 一旦创建了 SqlSessionFactory,就不再需要它了。

  • 局部变量

SqlSessionFactory:

  • 说白了就是可以想象成:数据库连接池

  • SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。

  • 最佳作用域是应用作用域

  • 最简单的就是使用单例模式或者静态单例模式

SqlSession

  • 连接到连接池的一个请求。

  • SqlSession的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。

  • 用完之后赶紧关闭,否则之后资源被占用!

这里面每一个mapper,就带代表一个具体的业务!

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

1、问题

数据库中的字段新建一个项目,拷贝之前的,测试实体类字段不一致的情况

public class User {
    private int id;
    private String name;
    private String password;

User{id=1, name='韩博轩', password='null'}

测试出现问题

//select * from mybatis.user where id = #{id}
//类型处理器
//select (id,name,pwd) from mybatis.user where id = #{id}

解决方法:

  • 起别名

        <select id="getUserById" parameterType="int" resultType="com.hbx.pojo.User">
            select id,name,pwd as password from mybatis.user where id = #{id}
        </select>

2、resultMap

结果集映射

id name pwd 
id name password
<!--结果集映射-->
    <resultMap id="UserMap" type="User">
<!-- column数据库中的字段,  property实体类的属性     -->
        <result column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="pwd" property="password"/>
    </resultMap>



    <select id="getUserById" resultMap="UserMap">
        select * from mybatis.user where id = #{id}
    </select>
  • resultMap 元素是 MyBatis 中最重要最强大的元素。

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

6、日志

6.1、日志工厂

如果一个数据库操作,出现了异常,日志就是最好的助手!

现在:日志工厂

Opening JDBC Connection
Created connection 134310351.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@80169cf]
==>  Preparing: select * from mybatis.user where id = ?
==> Parameters: 1(Integer)
<==    Columns: id, name, pwd
<==        Row: 1, 韩博轩, 001416
<==      Total: 1
User{id=1, name='韩博轩', password='001416'}
Resetting autocommit to true on JDBC Connection [com.mysql.jdbc.JDBC4Connection@80169cf]
Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@80169cf]
Returned connection 134310351 to pool.

6.2、Log4j

  1. 先导入log4j的包

  2. log4j.properties

  3. 配置log4j为日志的实现

    <settings>
    <!--    标准的日志工厂实现-->
    <!--    <setting name="logImpl" value="STDOUT_LOGGING"/>-->
        <setting name="logImpl" value="LOG4J"/>
    </settings>
  4. Log4j的使用!直接测试刚才运行的查询

简单使用

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

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

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

    logger.info("info:进入了log4j方法");
    logger.debug("debug:进入了log4j方法");
    logger.error("error:进入了log4j方法");

7、分页

  • 减少数据的处理量

使用limit分页

select * from user limit startIndex,pageSize

使用mybatis实现分页,核心SQL

  1. 接口

        //分页
        List<User> getUserByLimit(Map<String,Integer>map);
  2. Mapper.XML

    <!--    分页-->
        <select id="getUserByLimit" parameterType="map" resultMap="UserMap">
            select * from user limit #{startIndex},#{pageSize}
        </select>
  3. 测试

    @Test
    public void getUserByLimit(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        HashMap<String, Integer> map = new HashMap<>();
        map.put("startIndex",0);
        map.put("pageSize",2);

        List<User> userList = mapper.getUserByLimit(map);

        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.close();
    }

8、使用注解开发

8.1、面向接口编程

解耦

定义与实现的分离

8.2、使用注解开发

  1. 注解直接在接口上实现

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

  2. 需要在核心配置文件中绑定接口

    <!--绑定接口-->
        <mappers>
            <mapper class="com.hbx.dao.UserMapper"/>
        </mappers>

本质:反射机制实现

底层:动态代理!

mybatis详细的执行流程!

8.3、CRUD

我们可以在在工具类创建的时候自动提交事务!

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

编写接口,增加注解

 @Select("select * from user")
 List<User> getUsers();
 ​
 //方法存在多个参数,所有的参数前面必须加上@Param注解
 @Select("select * from user where id = #{id}")
 User getUserByID(@Param("id")int id);
 ​
 @Insert("insert into user (id,name,pwd) values (#{id},#{name},#{password})")
 int addUser(User user);
 ​
 ​
 @Update("update user set name = #{name},pwd=#{password} where id = #{id}")
 int updateUser(User user);
 ​
 ​
 @Delete("delete  from user where id = #{id}")
 int deleteUser(@Param("id")int id);

测试类

  @Test
     public void test(){
         SqlSession sqlSession = MybatisUtils.getSqlSession();
 ​
         //底层主要应用反射
         UserMapper mapper = sqlSession.getMapper(UserMapper.class);
 //        List<User> users = mapper.getUsers();
 //        for (User user : users) {
 //            System.out.println(user);
 //        }
 //        User userByID = mapper.getUserByID(1);
 //        System.out.println(userByID);
 ​
 //        mapper.addUser(new User(5,"要努力","00155454"));
 //        mapper.updateUser(new User(5,"我真的是","545165161"));
         mapper.deleteUser(5);
 ​
 ​
         sqlSession.close();
     }

注意 我们必须要将接口 注册绑定到配置文件中!!!

关于@Param()注解

  • 基本类型的参数或者String类型,需要加上

  • 引用类型不需要加

  • 如果只有一个基本类型的话可以忽略,但是建议大家加上

  • 我们在SQL中引用的就是我们这里的@Param()中设设定的属性名!

#{} ${}区别

$不安全!!!

9、Lombok

<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.18</version>
    </dependency>

</dependencies>

@Getter and @Setter @FieldNameConstants @ToString @EqualsAndHashCode @AllArgsConstructor:有参

@RequiredArgsConstructor

@NoArgsConstructor:无参 @Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog @Data:无参构造 get set tostring hashcode equals @Builder @SuperBuilder @Singular @Delegate @Value @Accessors @Wither @With @SneakyThrows

10、多对一处理

SQL:

CREATE TABLE `teacher` (
  `id` INT(10) 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(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  `tid` INT(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fktid` (`tid`),
  CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8INSERT 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');

按照查询嵌套处理

<mapper namespace="com.hbx.dao.StudentMapper">

<select id="getStudent" resultMap="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" resultMap="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="sid"/>
        <result property="name" column="sname"/>
        <association property="teacher" javaType="Teacher">
            <result property="name" column="tname"/>

        </association>
    </resultMap>

回顾MySQL 多对一查询

  • 子查询

  • 联表查询

11、一对多处理

老师、学生实体类

package com.hbx.pojo;

import lombok.Data;

import java.util.List;

@Data
public class Teacher {
    private int id;
    private String name;
    
    //一个老师拥有多个学生
    private List<Student> students;
}
package com.hbx.pojo;


import lombok.Data;

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

按照结果嵌套处理

<!--    按结果嵌套查询-->
<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 = #{tid}
</select>
    <resultMap id="TeacherStudent" type="Teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
<!--    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="getTeacher2" resultMap="TeacherStudent2">
    select * from teacher where id = #{tid}
</select>
<resultMap id="TeacherStudent2" type="Teacher">
    <collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId" column="id"/>

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

小结

  1. 关联 -association 【多对一】

  2. 集合- collection【一对多】

  3. javaType & ofType

    1. javaType 是来指定实体类中属性的类型‘

    2. ofType 用来指定映射到List 或者集合中的pojo类型 ,泛型中的约束类型!

注意点:

  • 保证SQL的可读性,尽量保证通俗易懂

  • 注意一对多和多对一中,属性名和字段的问题

  • 如果问题不好排查,可以使用日志,建议使用log4j

慢sql

面试高频:

  • MySQL引擎

  • innodb底层原理

  • 索引

  • 索引优化

12、动态SQL

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

如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

  • if

  • choose (when, otherwise)

  • trim (where, set)

  • foreach

CREATE TABLE `blog` (
`id` varchar(50) NOT NULL COMMENT '博客id',
`title` varchar(100) NOT NULL COMMENT '博客标题',
`author` varchar(30) NOT NULL COMMENT '博客作者',
`create_time` datetime NOT NULL COMMENT '创建时间',
`views` int(30) NOT NULL COMMENT '浏览量'
) ENGINE=InnoDB DEFAULT CHARSET=utf8

创建一个基础工程

  1. 导包

  2. 编写配置文件

  3. 编写实体类

     package com.hbx.pojo;
     ​
     import lombok.Data;
     ​
     import java.util.Date;
     @Data
     public class Blog {
         private int id;
         private String title;
         private String author;
         private Date create_time;
         private int views;
     }

  4. 编写实体类对应的mapper接口及其xml文件

IF

 <select id="queryBlogIF" parameterType="map" resultType="blog">
     select * from blog where 1 = 1
     <if test="title != null">
         and title = #{title}
     </if>
     <if test="author != null">
         and author = #{author}
     </if>
 </select>

choose (when, otherwise)

 <select id="queryBlogChoose" parameterType="map" resultType="blog">
     select * from blog
     <where>
         <choose>
             <when test="title != null">
                 title = #{title}
             </when>
             <when test="author != null">
                 and author = #{author}
             </when>
             <otherwise>
                 and views = #{views}
             </otherwise>
         </choose>
     </where>
 </select>

trim (where, set)

 <select id="queryBlogIF" parameterType="map" resultType="blog">
     select * from blog
     <where>
         <if test="title != null">
              title = #{title}
         </if>
         <if test="author != null">
              author = #{author}
         </if>
     </where>
 ​
 </select>
 <update id="updateBlog" parameterType="map">
     update blog
     <set>
         <if test="title != null">
             title = #{title},
         </if>
         <if test="author != null">
             author = #{author}
         </if>
     </set>
     where id = #{id}
 </update>
 <trim prefix="set" suffixOverrides=",">
     
 </trim>

所谓的动态SQL本质还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码

SQL片段

有的时候,我们可能会讲一些公共的部分抽取出来,实现复用

 <sql id="if-title-author">
         <if test="title != null">
                 title = #{title}
         </if>
         <if test="author != null">
                 and author = #{author}
         </if>
 </sql>
 <select id="queryBlogIF" parameterType="map" resultType="blog">
     select * from blog
     <where>
         <include refid="if-title-author"></include>
     </where>
 ​
 </select>
  1. 使用SQL标签抽取公共部分

     <sql id="if-title-author">
             <if test="title != null">
                     title = #{title}
             </if>
             <if test="author != null">
                     and author = #{author}
             </if>
     </sql>
  2. 在需要引用的地方使用include标签引用即可

     <select id="queryBlogIF" parameterType="map" resultType="blog">
         select * from blog
         <where>
             <include refid="if-title-author"></include>
         </where>
     </select>

注意事项:

  • 最好基于单表来进行SQL片段

  • 不要存在where标签

Foreach

 <!--
 我们现在传递一个万能的map,这个map中存在一个集合
 -->
     <select id="queryBlogForeach" parameterType="map" resultType="blog">
         select * from blog
         <where>
             <foreach collection="ids" item="id" open="and (" close=")" separator="or">
                 id = #{id}
             </foreach>
         </where>
     </select>
 ​

动态SQL就是在拼接SQL语句,我们只需要保证SQL的正确性,按照SQL的格式,去摆列组合就可以了

建议:

  • 现在MySQL中写出完整的SQL,在对应的去修改成为我们的动态SQL实现复用就可以了

13、缓存

一级缓存:

 SqlSession sqlSession = MybatisUtils.getSqlSession();
 UserMapper mapper = sqlSession.getMapper(UserMapper.class);
 List<User> users = mapper.queryUsers(1);
 System.out.println(users);
 System.out.println("===================================================");
 List<User> users2 = mapper.queryUsers(1);
 System.out.println(users2);
 sqlSession.close();

缓存失效:

  1. 查询不同东西

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

  3. 查询不同的mapper.xml

  4. 手动清理缓存

 sqlSession.clearCache();//手动清理缓存

小结:一级缓存默认是开启的,只在一次sqlSession中有效,也就是拿到连接关闭连接之间

一级缓存就是一个map

二级缓存

步骤

  1. 开启全局缓存

     <!--    开启全局缓存   -->
         <setting name="cacheEnabled" value="true"/>
  2. 在要使用二级缓存的mapper中开启

     <!--在当前Mapper.xml中使用二级缓存-->
     <cache />
  3. 也可以自定义一些参数

 <!--在当前Mapper.xml中使用二级缓存-->
 <cache eviction="FIFO"
        flushInterval="60000"
        size="512"
        readOnly="true"
 />

问题:

  1. 我们需要将实体类序列化!否则就会报错!

 public class User implements Serializable

小结:

  • 只要开启了二级缓存,在同一个mapper下有效

  • ‘所有的数据都会先放在一级缓存中

  • 只有当会话提交,或者关闭的时候才会提交到二级缓存中!

自定义缓存

 <dependency>
     <groupId>org.mybatis.caches</groupId>
     <artifactId>mybatis-ehcache</artifactId>
     <version>1.1.0</version>
 </dependency>

依赖

 <cache 
        type="org.mybatis.caches.ehcache.EhcacheCache"
 />
 <?xml version="1.0" encoding="UTF-8"?>
 <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
          updateCheck="false">
 ​
     <diskStore path="./tmpdir/Tmp_EhCache"/>
 ​
     <defaultCache
             eternal="false"
             maxElementsInMemory="10000"
             overflowToDisk="false"
             diskPersistent="false"
             timeToIdleSeconds="1800"
             timeToLiveSeconds="259200"
             memoryStoreEvictionPolicy="LRU"/>
 ​
     <cache
             name="cloud_user"
             eternal="false"
             maxElementsInMemory="5000"
             overflowToDisk="false"
             diskPersistent="false"
             timeToIdleSeconds="1800"
             timeToLiveSeconds="1800"
             memoryStoreEvictionPolicy="LRU"/>
 </ehcache>
 package com.hbx.utils;
 ​
 import org.apache.ibatis.cache.Cache;
 ​
 public class Mycache implements Cache {
 ​
     @Override
     public String getId() {
         return null;
     }
 ​
     @Override
     public void putObject(Object o, Object o1) {
 ​
     }
 ​
     @Override
     public Object getObject(Object o) {
         return null;
     }
 ​
     @Override
     public Object removeObject(Object o) {
         return null;
     }
 ​
     @Override
     public void clear() {
 ​
     }
 ​
     @Override
     public int getSize() {
         return 0;
     }
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值