MyBatis学习笔记

文章目录

一、MyBatis简介

是一个基于java的持久层框架,提供的持久层框架包括SQL Maps和Data Access Object(Dao)

1.MyBatis特性

  • MyBatis是一个持久层框架,支持定制化SQL、存储过程以及高级映射
  • 避免了几乎所有的JDBC代码和手动设置参数以及获取结果集
  • 可以使用简单的XML(将sql语句写到xml中)或注解用于配置和原始映射,将接口和java的pojo映射成数据库中的记录
  • 是一个半自动的ORM框架

2.MyBatis和其他持久化层技术对比

  • JDBC
    • SQL夹杂在java代码中,耦合度搞,导致硬编码内伤
    • 维护不易,频繁修改的情况多见
    • 代码冗长,开发效率低
  • Hibernate和JPA
    • 操作简便,效率高
    • 程序中的长难sql需要绕过框架
    • 内部自动生成的sql不容做特殊优化
    • 基于全映射的全自动框架,大量字段的pojo进行部分映射时比较困难
    • 反射操作太多,导致数据库性能下降
  • MyBatis
    • 轻量级、性能出色
    • SQL和java代码分开,java代码专注业务,sql语句专注数据

二、搭建MyBatis

1.1、创建Maven项目

修改mavaen的仓库和配置文件

1.2、导入依赖

mybatis、junit、mysql驱动

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

  <!-- https://mvnrepository.com/artifact/junit/junit -->
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
  </dependency>

  <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.3</version>
  </dependency>

</dependencies>

1.3、创建MyBatis的配置文件

两种配置文件:

  • 核心配置文件:用于配置连接数据库的环境以及MyBatis的全局配置信息
  • 映射文件:用来写SQL语句

习惯上命名为mybatis-config.xml,并非强制要求(整合ssm之后,可以省略)

核心配置文件

在main中的resource下创建mybatis-config.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--environments 配置连接数据库的文件-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/><!--事务管理类型-->
            <dataSource type="POOLED"><!--POOLED 表示使用数据库连接池-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!--mappers 引入映射文件-->
    <mappers>
        <mapper resource="org/mybatis/example/BlogMapper.xml"/>
    </mappers>
</configuration>
映射文件

看下面创建mapper接口中的映射文件

相关概念:ORM(Object Relationship Mapping)对象关系映射

  • 对象:java的实体类对象
  • 关系:关系型数据库
  • 映射:两者之间的对应关系
  1. 映射文件的命名规则:表对应的实体类的类名+Mapper.xml

    例如:表t_uer对应的实体类为User,他的映射文件的名字为:UserMapper.xml

  2. 映射文件的namespace属性的内容要和接口的全类名一致

  3. 映射文件中sql语句的id要和mapper接口中的方法名一样

1.4、创建mapper接口

mapper接口相当于原来的Dao,里面是操作数据库的方法。区别在于mapper仅仅是接口,不需要提供实现类

1)创建表
CREATE TABLE `t_user`(
username VARCHAR(20) NOT NULL PRIMARY KEY,
`password` VARCHAR(20)
)
2)创建pojo类

属性、有参、无参构造器、set、get方法、toString方法

public class User {
    private String username;
    private String password;

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public User() {
    }
}
3)创建接口(替代原来的Dao)
//代替原来的Dao,mybatis会调用接口中的方法
public interface UserMapper {
    int addUser();//添加用户信息的抽象方法
}
4)创建映射文件

看1.3的映射文件创建要求

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="love.junqing.mapper.UserMapper"><!--namespace:对应mapper接口的全类名-->
    <insert id="addUser"><!--sql语句的id要和方法名一致-->
        <!--具体执行的sql语句-->
        insert into `t_user` values("yfj","123456")
    </insert>

</mapper>
5)引入映射文件

核心配置文件中引入

<!--mappers 引入映射文件-->
<mappers>
    <mapper resource="UserMapper.xml"/><!--以resource为根目录-->
</mappers>

1.5、测试功能

创建一个类进行测试

public class FirstTest {
    @Test
    public void testadd() throws IOException {
        //1.加载核心配置文件(Resource是ibatis.io下面的)
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");//核心配置文件名
        //2.获取SqlSessionFactorBuilder
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder=new SqlSessionFactoryBuilder();//获取构建对象
        //3.通过构建对象获取SqlSessionFAcotry
        SqlSessionFactory build = sqlSessionFactoryBuilder.build(resourceAsStream);
        //4.获取sqlSession会话对象
        SqlSession sqlSession = build.openSession();
        //5.获取mapper接口对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);//返回接口的实现类(使用了代理模式)

        //6.测试功能
        int i = mapper.addUser();//调用方法,返回受影响的行数
        //7.因为核心配置文件中开启了事务,所以需要手动提交
        sqlSession.commit();
        System.out.println(i);
    }
}

1.6、功能优化

1.自动提交事务

sqlsession默认不自动提交事务如果获取sqlsession对象的时候,设置为true,就不需要手动提交事务

//4.获取sqlSession会话对象
SqlSession sqlSession = build.openSession(true);
2.加入log4j日志功能
  1. 加入log4j的依赖
    <!-- log4j日志 -->
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.17</version>
    </dependency>
    
  2. 加入log4j的配置文件

    文件名固定:log4j.xml

    存放的位置:src/main/resources

    日志的级别:FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试)

    从左到右打印的内容越来越详细

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"><!--爆红也没关系-->
        <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
            <param name="Encoding" value="UTF-8" />
            <layout class="org.apache.log4j.PatternLayout">
                <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS}
    %m (%F:%L) \n" />
            </layout>
        </appender>
        <logger name="java.sql">
            <level value="debug" />
        </logger>
        <logger name="org.apache.ibatis">
            <level value="info" />
        </logger>
        <root>
            <level value="debug" />
            <appender-ref ref="STDOUT" />
        </root>
    </log4j:configuration>
    
3.添加增加和修改功能
  1. 在接口中添加抽象方法
    public interface UserMapper {
        int addUser();
        int delUser();
        int updateUser();
    }
    
  2. 在映射文件中添加对应的标签和语句
    <!--    int delUser();-->
        <delete id="delUser">
            delete from `t_user` where username="yfj"
        </delete>
    <!--    int updateUser();-->
        <update id="updateUser">
            update `t_user` set password="456" where username="zyj"
        </update>
    
  3. 测试相关方法
    @Test
    public void testdel() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory build = sqlSessionFactoryBuilder.build(resourceAsStream);
        SqlSession sqlSession = build.openSession(true);
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.delUser();
    }
    @Test
    public void testupd() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory build = sqlSessionFactoryBuilder.build(resourceAsStream);
        SqlSession sqlSession = build.openSession(true);
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.updateUser();
    }
    
4.添加查询功能

首先确定查询出来的数据需要转化为什么类型(对象还是集合)

查询功能的标签必须设置resultType或者resultMap,从而说明结果类型

  • resulType:设置默认的映射关系
  • resultMap:设置自定义的映射关系(字段名一致赋值,字段名不一致则不赋值)
  1. 接口中添加方法
    //查询一条信息
    User selectUser();
    //查询所有信息
    List<User> allUser();
    
  2. 映射文件的标签中**需要添加resultType或者resultMap**
    <!--    //查询一条信息-->
    <!--    User selectUser();-->
        <select id="selectUser" resultType="love.junqing.pojo.User">
            select * from t_user where password="456"
        </select>
    <!--    //查询所有信息-->
    <!--    List<User> allUser();-->
        <select id="allUser" resultType="love.junqing.pojo.User">
            select * from t_user
        </select>
    
  3. 测试方法
    @Test
    public void testselect() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");//获取字节输入流
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();//获取工厂构建对象
        SqlSessionFactory build = sqlSessionFactoryBuilder.build(resourceAsStream);
        SqlSession sqlSession = build.openSession(true);
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.selectUser();
        System.out.println(user);
    }
    @Test
    public void testselectAll() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory build = sqlSessionFactoryBuilder.build(resourceAsStream);
        SqlSession sqlSession = build.openSession(true);
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = mapper.allUser();
        for (User user:users){
            System.out.println(user);
        }
    }
    

三、核心配置文件详解(了解即可)

1.environment

environments:用来配置多个数据库的环境

dafault:设置默认使用的环境id

environment:配置某个具体的环境

id:表示所连接数据库环境的唯一标识(不能重复)

transactionManager:表示事务管理方式(type属性有两个值)

  • JDBC:表示当前环境中,执行sql时,使用的是jdbc中原生的事务管理方式
  • MANAGED:被管理(例如Spring)

dataSource:配置数据源(type属性有三个值)

  • POOLED:表示使用数据库连接池
  • UNPOOLED:表示不适用数据库连接池
  • JNDI:表示使用上下文中的数据源

2.properties

把数据库的信息放到配置文件中

  1. properties配置文件
    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/mybatis
    jdbc.username=root
    jdbc.password=123456
    
  2. 引入properties文件
    <properties resource="jdbc.properties"></properties>
    
  3. 将信息写入
    <property name="driver" value="${jdbc.driver}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
    

3.typeAliases

用来设置类型别名:应为接口的配置文件中,查询的时候resultType里面的包路径很长

typeAliases标签要放到properties标签后面

<typeAliases>
    <typeAlias type="love.junqing.pojo.User" alias="User"></typeAlias>
</typeAliases>
  1. type是全路径

  2. alias是别名(可以设置,可以不设置)

  3. 设置了之后,值就是设置的;若没有设置,就是类名(不区分大小写)

  4. 设置完了之后,接口的配置文件的resultType可以使用别名

  5. 一般使用下面这种方式,使用package标签,他的name设置包名,这样就将包下面的所有类都设置了别名(类名不区分大小写)

    <typeAliases>
        <package name="love.junqing.pojo.User"/>
    </typeAliases>
    

4.mappers

批量引入映射文件

可以使用package标签,直接把一整个包弄进来

使用要求:

  1. package的路径使用 .

  2. mapper接口所在的包要和映射文件所在的包名一致

    mapper接口的配置文件在放在resources中(创建包的时候使用 / 不用 . )

  3. mapper接口要和映射文件的名字一致

<mappers>
    <package name="love.junqing.mapper"/>
</mappers>

四、IDEA设置核心配置文件模板

  1. 创建mybatis的核心配置文件
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//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="${jdbc.driver}"/>
                    <property name="url" value="${jdbc.url}"/>
                    <property name="username" value="${jdbc.username}"/>
                    <property name="password" value="${jdbc.password}"/>
                </dataSource>
            </environment>
        </environments>
        <mappers>
            <mapper resource="UserMapper.xml"/>
        </mappers>
    </configuration>
    
  2. 创建一个properties配置文件
    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/mybatis
    jdbc.username=root
    jdbc.password=123456
    
  3. 核心配置文件中引入properties配置文件
    <properties resource="jdbc.properties"></properties>
    
  4. 核心配置文件引用配置文件中的值
    <dataSource type="POOLED">
        <property name="driver" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </dataSource>
    
  5. 设置类型别名(如果有需要的话)
  6. 设置映射文件
  7. 找到idea的Setting–>Editor–>File and Code–>点击加号,设置name为mybaits-config,后缀为xml,把模板粘贴进去

    image-20230418130432076

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "https://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <properties resource="jdbc.properties"></properties>
        <typeAliases>
            <package name=""/><!--类型别名-->
        </typeAliases>
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="${jdbc.driver}"/>
                    <property name="url" value="${jdbc.url}"/>
                    <property name="username" value="${jdbc.username}"/>
                    <property name="password" value="${jdbc.password}"/>
                </dataSource>
            </environment>
        </environments>
        <mappers>
            <package name=""/><!--映射文件所在的包,需要和接口的包名一致-->
        </mappers>
    </configuration>
    

五、IDEA设置映射文件模板

根据功能进行划分

  1. 根据上面四的路径,找到创建模板路径,粘贴进去
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace=""><!--namespace:对应接口的全类名-->
      
    </mapper>
    

六、将获取SqlSession抽取为工具类

public class SqlUtils {
    public static SqlSession getSqlSession(){
        SqlSession sqlSession=null;
        try {
            InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            SqlSessionFactory build = sqlSessionFactoryBuilder.build(resourceAsStream);
            sqlSession = build.openSession(true);
            
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sqlSession;
    }
}

七、MyBatis获取参数值的两种方式(重点)

Mybatis获取参数值的两种方式:${ }和#{ }

  • ${ }:本质就是字符串拼接(会造成sql注入)
  • #{ }:本质就是占位符赋值

1.单个字面类型的参数

可以通过${ }和#{ }以任意的名称获取参数值

但是需要注意${ }需要使用单引号引起来

1.${ }

  1. Mapper接口

    User getUserByUsername(String username);
    
  2. 映射文件

    <select id="getUserByUsername" resultType="User">
        select * from t_user where username='${username}'<!--如果使用${}则需要加上单引号,里面的参数名随便,只是起一个占位置的作用-->
    </select>
    

2.#{ }

  1. 映射文件

    select * from t_user where username= #{username}<!--#{}不需要单引号-->
    

2.多个字面类型的参数

如果传入多个参数,mabatis会把参数放到一个map中,以两种方式存储

  • 以arg0,arg1…为键,以参数为值
  • 以param1,param2…为键,以参数位为值

可以使用${ }或#{ }以键的方式访问值

select * from t_user where username= #{arg0} and password=#{param2}<!--arg从0开始,param从1开始,可以混着用-->

3.map集合类型的参数

如果mapper接口方法的参数有多个的时候,可以手动将参数放到map集合中,然后将集合设置为查询的参数

  1. mapper接口

    User getUserByUsername(Map map);//查询的参数以集合的形式传入
    
  2. 映射文件

    <select id="getUserByUsername" resultType="User">
        select * from t_user where username= #{username} and password=#{password}<!--查询的时候使用的是我们自己定义的键-->
    </select>
    
  3. 测试

    Map<String, Object> map = new HashMap<>();
    map.put("username","zyj");
    map.put("password","456");
    User userByUsername = mapper.getUserByUsername(map);
    System.out.println(userByUsername);
    

4.对象类型的参数

如果传入的是一个对象类型的参数,可以通过属性名获取值

  • 这里sql语句中的参数不是对象的属性,而是对象中set和get方法去掉set或者get的名字
  1. mapper接口

    int addUser(User user);
    
  2. 映射文件(里面的参数是get或者set方法去掉set或者get得到的)

    <insert id="addUser">
        insert into t_user values(#{username},#{password})<!--通过get或者set方法找到值-->
    </insert>
    
  3. 测试

    Integer i = mapper.addUser(new User("yfj","123456"));
    

5.使用@Param命名参数

传入多个参数的时候,mybatis会自动将我们的参数放入一个map集合中,但是名字是arg,不是我们自定义的。

当我们使用@Param后,就可以通过自己设置的键访问(也可以使用param1,parma2访问)

  1. mapper接口

    User getUserByUsernameAndP(@Param("username") String username,@Param("password")String password);
    
  2. 映射文件

    <select id="getUserByUsernameAndP" resultType="User">
        select * from t_user where username= #{username} and password=#{password}<!--查询的时候使用的是我们自己定义的键-->
    </select>
    
  3. 测试

    User yfj = mapper.getUserByUsernameAndP("yfj", "123456");
    

八、Myabtis的各种查询功能

  • 如果查询出来的对象只有一条,可以通过实体类接收对象,也可以通过list集合接收
  • 如果查询出的是数据有多条,不能通过实体类对象来接收,因为会报异常,可以使用list接收对象集合
  • 如果查询出来的数据没有对应的实体类,可以用map接收

1.查询结果是一个实体类对象

Myabatis中设置了默认的类型别名

  • java.lang.Integer–>int,Integer
  • int–>_int, _integer
  • Map–>map
  • String—>string
  1. 用实体类接收
    • mapper接口

      User getUserByUsername(Map map);
      
    • 映射文件

      <select id="getUserByUsername" resultType="User">
          select * from t_user where username= #{username} and password=#{password}<!--查询的时候使用的是我们自己定义的键-->
      </select>
      
  2. 用list集合接收一个实体类
    • mapper接口

      List getUserToList(@Param("username") String uername);
      
    • 映射文件

      <select id="getUserToList" resultType="User">
          select * from t_user where username= #{username}
      </select>
      

2.查询结果是一个Map类型

如果查询结果的返回类型没有实体类可以接受,那么可以将结果放到Map中,以键值对的形式放到map集合中

  1. mapper接口

    Map<String,Object> getUserToMap(@Param("username") String uername);
    
  2. 映射文件

    <select id="getUserToMap" resultType="Map">
        select * from t_user where username= #{username}
    </select>
    
  3. 测试方法

    Map yfj = mapper.getUserToMap("yfj");
    System.out.println(yfj);
    

3.查询结果是多个对象

  1. 查询结果是多个实体类对象

    就是平常的方法

  2. 查询结果是多个map集合

    有两个方法:

    1. 可以是使用List存储map集合,也就是下面给的案例
    2. 也可以方法的返回类型就是Map,但是在方法上加一个@MapKey()注解,注解里面的值是一个键,键的值不会 重复,那么就会把这个独一无二的一个键作为map的键
    1. mapper接口

      List<Map<String,Object>> getUsersToMap();
      
    2. 映射文件

      <select id="getUsersToMap" resultType="map">
          select * from t_user
      </select>
      
    3. 测试方法

      List<Map<String, Object>> usersToMap = mapper.getUsersToMap();
      System.out.println(usersToMap);
      

九、特殊SQL的执行

某些sql语句使用#{ }会出现问题,所以就需要使用${ }查询

1.模糊查询(3种方法)

(1)${ }方法

select * from t_user where username like '%${username}%' <!--% 表示匹配任意多个字符,${} 里面是传入的参数-->

(2)concat的字符串拼接

select * from t_user where username like concat('%',#{username},'%') <!--三部分拼接到一起,#{}里面是传入的参数-->

(3)双引号直接拼接(最常用)

select * from t_user where username like "%"#{username}"%" <!--使用的是双引号“ ”-->

2.批量删除

<delete id="deletesome">
        delete from t_user where id in (${ids})
    </delete>

3.动态设置表名

<select id="getUserToList" resultType="User">
    select * from ${tableNAme} <!--表名是传进来的-->
</select>

4.获取自增的主键

案例:user对象的id属性是自动增长的,当我们执行一个insert语句把user对象添加进去的同时想要获取user对象的id属性

  • useGeneratedKeys:表示当前标签中的sql使用了自增的id
  • keyProperty:从sql获取到的自动增长的属性值给java对象的哪个属性
  1. 映射文件

    <insert id="addUser" useGeneratedKeys="true" keyProperty="id">
        insert into t_user values(null,#{username},#{password})<!--将获取到的自增id,赋给java对象的id属性-->
    </insert>
    
  2. 测试方法

    User uer=new User(null,"yfj","123");//创建了一个user对象,这个时候user对象是没有id值的
    mapper.addUser(user);//执行sql
    System.out.println(user);//这个时候user对象的id有了值
    

十、解决字段名不一致(3种方法)

字段名和属性名不一致,的处理方法

例如:mysql字段名带下划线,java类中不带下划线

处理方法(两种):

  1. sql语句中设置别名 select user_name username,emp_age age …
  2. 使用Myabtis的全局配置
  3. 使用resultMap

方法一:sql语句中使用别名

select user_name username,emp_age age from t_user 

方法二:设置Mybatis全局配置

放在properties标签下面

将下划线自动映射成驼峰 user_name -->userName

<settings>
    <!--将下划线自动映射成驼峰 user_name -》userName -->
    <setting name="mapUnderscoreToCamelCase" value="true"/><!--true表示开启-->
</settings>

方法三:使用resultMap

设置resultMap标签id属性是唯一标识,就是select标签resultMap的值

type属性的值就是对应的实体类类型

id标签用于主键的关系:property是java对象的属性名,column是sql中的字段名

result标签用于普通字段的关系:property是java对象的属性名,column是sql中的字段名

使用resultMap需要把所有的属性都设置

<!--type属性的值就是对应的实体类名-->
<resultMap id="UserResultMap" type="User">
    <!--property是java对象的属性名,column是sql中的字段名-->
    <id property="username" column="user_name"></id>
    <result property="password" column="password"></result>
    <result property="sex" column="t_sex"></result>
</resultMap>

<!--resultMap="UserResultMap" 表示使用上面的resultMap-->
<select id="allUser" resultMap="UserResultMap">
    select * from t_user
</select>

十一、resultMap的功能

1.resultMap的功能

  • 解决字段名和对象属性名不一致的情况(看上面的笔记)
  • 解决多对一的映射关系
  • 解决一对多的映射关系

2.多对一的映射关系(3种方式)

操作背景:查询员工的信息及所属部门的信息

出现问题:员工类没有对应的属性去接收部门的信息,所以需要resultMap自定义映射信息

所有方法都需要的公共部分

  1. 在多的pojo中创建一的对象

    例如:一个部门对应多个员工,就在员工类中创建部门对象

    private Dept dept;
    
  2. 设置get和set方法
    public Dept getDept() {
        return dept;
    }
    
    public void setDept(Dept dept) {
        this.dept = dept;
    }
    
  3. 修改构造器和toString方法

a>方法一:级联属性赋值(resultMap映射到属性对象的属性中)

<resultMap id="empDeptMap" type="Emp">
<id column="eid" property="eid"></id>
<result column="ename" property="ename"></result>
<result column="age" property="age"></result>
<result column="sex" property="sex"></result>
<result column="did" property="dept.did"></result>
<result column="dname" property="dept.dname"></result>
</resultMap>
<!--Emp getEmpAndDeptByEid(@Param("eid") int eid);-->
<select id="getEmpAndDeptByEid" resultMap="empDeptMap">
select emp.*,dept.* from t_emp emp left join t_dept dept on emp.did =
dept.did where emp.eid = #{eid}
</select>

b>association处理映射关系

  1. 首先把有对应关系的写好
  2. 然后使用association标签,给属性对象赋值
  3. association标签中
    • property:表示对象中的属性名
    • javaType:表示这一部分对应的对象类型
  4. 然后再association里面在使用id、reult标签
<resultMap id="empDeptMap" type="Emp">
    <id column="eid" property="eid"></id>
    <result column="ename" property="ename"></result>
    <result column="age" property="age"></result>
    <result column="sex" property="sex"></result>
<!--给属性对象赋值-->
    <association property="dept" javaType="Dept"><!--property:表示Emp对象中的属性名  javaType:表示这个属性对应的对象类型-->
        <id column="did" property="did"></id>
        <result column="dname" property="dname"></result>
    </association>
</resultMap>
<!--Emp getEmpAndDeptByEid(@Param("eid") int eid);-->
<select id="getEmpAndDeptByEid" resultMap="empDeptMap">
select emp.*,dept.* from t_emp emp left join t_dept dept on emp.did =
dept.did where emp.eid = #{eid}
</select>

c>分步查询(重要)

也是使用association,但是是使用多条sql语句查询

先查询能直接查到的,然后利用查到的,去查另外查不到的部分

例如:需要查询员工和他的部门信息

先查询员工的信息,然后利用查询出来的所属部门,去查询部门

分布查询优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息(settings标签)

  • lazyLoadingEnable:延迟加载的全局开关,开启时,所有关联对象都会延迟加载(所以需要开启)
  • aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性(所以需要关闭)
延迟加载

需要访问哪些信息,就会去加载,没有访问的就不会去加载

<settings>
    <setting name="lazyLoadingEnable" value="true"/>
</settings>
  • 如果有些sql语句不需要延迟加载可以设置association标签的fetchType属性(lazy为延迟加载,eager为立即加载)
  1. 第一步查询员工信息
    • mapper接口

      Emp getEmpByStep(@Param("eid") int eid);
      
    • 映射文件

      <resultMap id="empDeptStepMap" type="Emp">
          <id column="eid" property="eid"></id>
          <result column="ename" property="ename"></result>
          <result column="age" property="age"></result>
          <result column="sex" property="sex"></result>
          <!--select:第二步查询的方法全路径(mapper接口名.方法名)-->
          <association property="dept"
              select="com.atguigu.MyBatis.mapper.DeptMapper.getEmpDeptByStep" column="did"><!--column:将查询结果中的某个字段设置为分步查询的条件-->
          </association>
      </resultMap>
      <!--Emp getEmpByStep(@Param("eid") int eid);-->
      <select id="getEmpByStep" resultMap="empDeptStepMap">
      select * from t_emp where eid = #{eid}
      </select>
      
  2. 第二步查询部门信息
    • mapper接口

      Dept getEmpDeptByStep(@Param("did") int did);
      
    • 映射文件

      <!--Dept getEmpDeptByStep(@Param("did") int did);-->
      <select id="getEmpDeptByStep" resultType="Dept">
      	select * from t_dept where did = #{did}
      </select>
      

3.一对多的映射关系(2种)

一对多公共部分

在一的pojo中创建一的集合

例如:一个部门对应多个员工,就在部门类中创建员工集合,然后设置get、set、toString方法

private List<User> users;

(1)通过collection解决一对多

resultMap直接能查询出来的就是老步骤

resultMap中使用collection标签

  • property:表示对象中的属性对象名(部门类中的员工对象名)
  • ofType:集合中存放的是什么类型数据

注意:collection标签中不要再设置部门类了(否则会套娃)

  • mapper接口

    Dept getDeptEmpByDid(@Param("did") int did);
    
  • 映射文件

    <resultMap id="deptEmpMap" type="Dept">
        <id property="did" column="did"></id>
        <result property="dname" column="dname"></result>
        <!--
        ofType:设置collection标签所处理的集合属性中存储数据的类型
        -->
        <collection property="emps" ofType="Emp">
            <id property="eid" column="eid"></id>
            <result property="ename" column="ename"></result>
            <result property="age" column="age"></result>
            <result property="sex" column="sex"></result>
        </collection>
    </resultMap>
    
    <select id="getDeptEmpByDid" resultMap="deptEmpMap">
        select dept.*,emp.* from t_dept dept left join t_emp emp on dept.did =
        emp.did where dept.did = #{did}
    </select>
    

(2)通过分步解决一对多

  1. 第一步:只需要查询部门信息
    • mapper接口

      Dept getDeptByStep(@Param("did") int did);
      
    • 映射文件

      <resultMap id="deptEmpStep" type="Dept">
      <id property="did" column="did"></id>
      <result property="dname" column="dname"></result>
      <collection property="emps" fetchType="eager"
      select="com.atguigu.MyBatis.mapper.EmpMapper.getEmpListByDid" column="did">
      </collection>
      </resultMap>
      <!--Dept getDeptByStep(@Param("did") int did);-->
      <select id="getDeptByStep" resultMap="deptEmpStep">
      select * from t_dept where did = #{did}
      </select>
      
  2. 第二步:设置collectuion标签
    <!--property:部门类种对应的用户对象名
    	fetchType:加载方式(立即加载、延迟加载)
    	select:调用的查询方法全路径
    	column:给下一步的条件
    -->
    <collection property="emps" 
                fetchType="eager"
                select="com.atguigu.MyBatis.mapper.EmpMapper.getEmpListByDid" 	
                column="did">
    </collection>
    
  3. 第三步:通过第二步给的条件查询用户信息
    • mapper接口

      List<Emp> getEmpListByDid(@Param("did") int did);
      
    • 映射文件

      <select id="getEmpListByDid" resultType="Emp">
      select * from t_emp where did = #{did}
      </select>
      

十二、动态SQL

存在的意义是为了拼接sql语句

主要用于:多条件查询(例如:淘宝条件的筛选)

1.if标签

可以根据test属性中的表达式决定是否拼接到sql中,如果传递过来的符合条件,就执行标签里面的

  • test属性:是判断的条件,如果返回对象中有这个属性,那么可以直接使用

  • 如果有多个if标签,需要使用and 或者 or进行拼接

  • 建议where后面加一个条件1=1,防止第一个if标签里面的条件不成里(缺点b)

    <select id="allUser" resultType="User">
        select * from t_user where 1=1
        <if test="username!=null and username!='' "><!--里面的参数如果传进来的对象有,可以直接调用-->
            and username=#{username}<!--执行的条件,#号里面是传递进来的参数-->
        </if>
        <if test="password!=null and password!='' ">
            and password=#{password}<!--因为是和前面的条件进行拼接,所以需要使用and或者or-->
        </if>
    </select>
    

2.where标签

用来解决if标签出现的问题(不需要再自己加1=1的条件,同时会自动删除if标签中的and 、or)

  • 当where标签中的条件成立时,会自动生成where关键字,并且将内容前多余的and 或 or 去掉

  • 当where 标签中的条件都不成立时,此时where标签没有任何效果

  • 注意:只能去掉内容前的多余and和or,不能去掉内容后的and和or

    <select id="allUser" resultType="User">
        select * from t_user
        <where>
            <if test="username !=null and username!='' ">
                 username=#{username}
            </if>
            <if test="password !=null and password!='' ">
                and password=#{password}
            </if>
        </where>
    </select>
    

3.trim标签

用来解决where不能去掉内容后面and或or的问题

  • prefix属性:在trim标签中的内容前****添加指定内容
  • suffix属性:在trim标签中的内容后添加指定内容
  • suffixOverrides属性:在trim标签中的内容后面去掉指定内容
  • perfixOverrides属性:在trim标签中的内容前面去掉指定内容
  • 说明:如果标签中没有内容,则trim标签没有任何效果
<select id="allUser" resultType="User">
    select * from t_user
    <trim prefix="where" suffixOverrides="and|or" ><!--因为缺少where所以前缀加一个where,后面去掉and或or-->
        <if test="username !=null and username!='' ">
             username=#{username} and
        </if>
        <if test="password !=null and password!='' ">
            password=#{password}
        </if>
    </trim>
</select>

4.choose、when、otherwise标签

choose是父标签,when、otherwose都需要写在choose标签里面

相当于switch—case:choose表示switch,when表示case,otherwise表示default

when不会穿透

注意:when至少要有一个,otherwise最多有一个

<select id="allUser" resultType="User">
    select * from t_user
    <where>
        <choose>
            <when test="username !=null and username!='' ">
                username=#{username}
            </when>
            <when test="password !=null and password!='' ">
                password=#{password}
            </when>
            <otherwise><!--都不成立才会执行的操作-->
                dept=#{dept}
            </otherwise>
        </choose>
    </where>
</select>

5.foreach标签

用来实现批量删除和批量添加功能(因为传递进来的是一个List集合或者数组)

collection属性:就是传进来的数组名

item属性:表示数组中的元素(随便起个名字,只要#{}里面用他就行)

separator属性:表示分隔符

open属性:表示foreach以什么开始

close属性:表示foreach以什么结束

(1)通过数组实现批量删除

  • mapper接口

    Integer deleteUser(@Param("usernames") String []usernames);
    
  • 映射文件(使用in的方式)

    <!--    Integer deleteUser(@Param("usernames") Integer []usernames);-->
        <delete id="deleteUser">
            delete from t_user where username in
            <foreach collection="usernames" item="username" separator=","  open="(" close=")">
                #{username}
            </foreach>
        </delete>
    
  • 映射文件(使用or的方式)

    <!--    Integer deleteUser(@Param("usernames") Integer []usernames);-->
        <delete id="deleteUser">
            delete from t_user where
            <foreach collection="usernames" item="username" separator="or"  open="(" close=")">
                username=#{username}
            </foreach>
        </delete>
    

(2)通过List集合实现批量添加

  • mapper接口

    Integer addUsers(@Param("users") List<User> users);
    
  • 映射文件

    <!--    Integer addUsers(@Param("users") List<User> users);-->
        <insert id="addUsers">
            insert into t_user values
            <foreach collection="users" item="user" separator=",">
                (#{user.username},#{user.password})
            </foreach>
        </insert>
    

6.sql标签

可以将常用的字段存放起来,需要使用的时候直接引用

使用include标签引用,refid属性对应sql标签的id

<!--设置sql片段-->
<sql id="userinform">username,password</sql>
<!--引用sql片段-->
<select id="allUser" resultType="User">
    select <include refid="userinform"></include>from t_user
</select>

十三、MyBatis的缓存

1.MyBatis的一级缓存

一级缓存默认开启,是SqlSession级别的,只对查询功能有效

SqlSession就是我们java代码获取mapper对象的那个sqlsession对象

只要我们使用的是同一个SqlSession对象,那么就会存在缓存,即使不使用相同的mapper对象

如果存在缓存,查询相同数据的时候,就不会再执行sql语句,而是直接从缓存中取

  • 使一级缓存失效的四种情况
    1. 不适用同一个SqlSession
    2. 使用同一个SqlSession,但是查询条件不同
    3. 使用同一个SqlSession进行了两次查询,但是中间执行了一个增删改操作
    4. 使用同一个SqlSession进行查询操作,但是手动清除了缓存(sqlSession的clearCache方法)

2.MyBatis的二级缓存

二级缓存是SqlSessionFactory级别的,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取

  • 二级缓存开启的必要条件
    1. 在核心配置文件中,设置全局配置属性cacheEnabled=“true”(默认为true,不需要设置)
    2. 在映射文件中设置标签<cache/>
    3. 二级缓存必须在SqlSession关闭或提交之后有效(调用sqlSession.close( )或者sqlSession.commit( ))
    4. 查询的数据所转换的实体类类型必须实现序列化的接口(需要手动去实现Serializable接口)
  • 使二级缓存失效的情况
    1. 两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效

3.二级缓存的配置文件

在mapper配置文件中添加cache标签可以设置一些属性

  • eviction属性:缓存回收策略

    LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象【默认使用】。

    FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。

    SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。

    WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

    默认的是 LRU。

  • flushInterval属性:刷新间隔(二级缓存多长时间刷新一次),单位毫秒

    默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新

  • size属性:引用数目,正整数

    代表缓存最多可以存储多少个对象,太大容易导致内存溢出

  • readOnly属性:只读,true/false

    true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了 很重要的性能优势。

    false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是 false。

4.MyBatis缓存查询的查询顺序

  • 先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
  • 如果二级缓存没有命中,再查询一级缓存
  • 如果一级缓存也没有命中,则查询数据库
  • SqlSession关闭之后,一级缓存中的数据会写入二级缓存

5.整合第三方缓存EHCache

只能用第三方工具代替Myabtis的二级缓存

下面的只需要会配就行

说明:虽然使用的是第三方缓存,但是实现的功能还是一样的,依旧是SqlSessionFactory级别

(1)引入依赖

<!-- Mybatis EHCache整合包 -->
<dependency>
  <groupId>org.mybatis.caches</groupId>
  <artifactId>mybatis-ehcache</artifactId>
  <version>1.2.1</version>
</dependency>
<!-- slf4j日志门面的一个具体实现 -->
<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>1.2.3</version>
</dependency>

各jar包的功能:

mybatis-ehcache:Mybatis和EHCache的整合包

ehcache:EHCache核心包

slf4j-api:SLF4J日志门面包

logback-classic:支持SLF4J门面接口的一个具体实现

(2)创建EHCache的配置文件ehcache.xml

放在resources文件夹下

<?xml version="1.0" encoding="utf-8" ?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="../config/ehcache.xsd"><!--报错不用管-->
    <!-- 磁盘保存路径 -->
    <diskStore path="D:\atguigu\ehcache"/>
    <defaultCache
            maxElementsInMemory="1000"
            maxElementsOnDisk="10000000"
            eternal="false"
            overflowToDisk="true"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
    </defaultCache>
</ehcache>

(3)设置二级缓存的类型

用在映射文件中

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

(4)加入logback日志

存在SLF4J时,作为简易日志的log4j将失效,此时我们需要借助SLF4J的具体实现logback来打印日志。 创建logback的配置文件logback.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
    <!-- 指定日志输出的位置 -->
    <appender name="STDOUT"
              class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
    <!-- 日志输出的格式 -->
    <!-- 按照顺序分别是:时间、日志级别、线程名称、打印日志的类、日志主体内容、换行 -->
    <pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger]
    [%msg]%n</pattern>
    </encoder>
    </appender>
    <!-- 设置全局日志级别。日志级别按顺序分别是:DEBUG、INFO、WARN、ERROR -->
    <!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
    <root level="DEBUG">
        <!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender -->
        <appender-ref ref="STDOUT" />
    </root>
    <!-- 根据特殊需求指定局部日志级别 -->
    <logger name="com.atguigu.crowd.mapper" level="DEBUG"/>
</configuration>

十四、MyBatis的逆向工程

正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程 的。

逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源: Java实体类、Mapper接口、Mapper映射文件

1.逆向工程的创建步骤(清新简洁版)

(1)添加依赖

<!-- 依赖MyBatis核心包 -->
<dependencies>
  <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.7</version>
  </dependency>
    
   <!-- https://mvnrepository.com/artifact/junit/junit -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>

    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.3</version>
    </dependency>
    <!-- log4j日志 -->
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.17</version>
    </dependency>
</dependencies>
<!-- 控制Maven在构建过程中相关配置 -->
<build>
  <!-- 构建过程中用到的插件 -->
  <plugins>
    <!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 -->
    <plugin>
      <groupId>org.mybatis.generator</groupId>
      <artifactId>mybatis-generator-maven-plugin</artifactId>
      <version>1.3.0</version>
      <!-- 插件的依赖 -->
      <dependencies>
          
        <!-- 逆向工程的核心依赖 -->
        <dependency>
          <groupId>org.mybatis.generator</groupId>
          <artifactId>mybatis-generator-core</artifactId>
          <version>1.3.2</version>
        </dependency>
        <!-- 数据库连接池 -->
        <dependency>
          <groupId>com.mchange</groupId>
          <artifactId>c3p0</artifactId>
          <version>0.9.2</version>
        </dependency>
        <!-- MySQL驱动 -->
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>5.1.8</version>
        </dependency>
      </dependencies>
    </plugin>
  </plugins>
</build>

(2)创建MyBatis的核心配置文件

(3)创建逆向工程的配置文件

文件名必须是:generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"><!--会爆红,不需要管-->
<generatorConfiguration>
        <!--targetRuntime: 执行生成的逆向工程的版本
        MyBatis3Simple: 生成基本的CRUD(清新简洁版)
        MyBatis3: 生成带条件的CRUD(奢华尊享版)
        -->
        <context id="DB2Tables" targetRuntime="MyBatis3Simple">
        <!-- 数据库的连接信息 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
        connectionURL="jdbc:mysql://localhost:3306/mybatis"
        userId="root"
        password="123456">
        </jdbcConnection>
        <!-- javaBean的生成策略
        targetPackage:bean生成在哪个包
        targetProject:包生成在哪里-->
        <javaModelGenerator targetPackage="com.junqing.mybatis.bean"
        targetProject=".\src\main\java">
        <property name="enableSubPackages" value="true" /><!--是否自动生成包-->
        <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- SQL映射文件的生成策略 -->
        <sqlMapGenerator targetPackage="com.junqing.mybatis.mapper"
        targetProject=".\src\main\resources">
        <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>
        <!-- Mapper接口的生成策略 -->
        <javaClientGenerator type="XMLMAPPER"
        targetPackage="com.junqing.mybatis.mapper" targetProject=".\src\main\java">
        <property name="enableSubPackages" value="true" />
        </javaClientGenerator>
        <!-- 逆向分析的表 -->
        <!-- tableName:数据库中的表名-->
        <!-- domainObjectName:生成的实体类的类名 -->
        <!-- mapper接口和映射文件会根据domainObjectName自动生成 -->
        <table tableName="t_user" domainObjectName="User"/>
        </context>
</generatorConfiguration>

(4)使用插件执行功能

点击右侧Maven的plugins的mybatis-generator插件

2.逆向工程的创建步骤(奢华尊享版)

创建步骤一样,只需要把generatorConfig的标签中的targetRuntime属性的值改为MyBatis3即可

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"><!--会爆红,不需要管-->
<generatorConfiguration>
        <!--targetRuntime: 执行生成的逆向工程的版本
        MyBatis3Simple: 生成基本的CRUD(清新简洁版)
        MyBatis3: 生成带条件的CRUD(奢华尊享版)
        -->
        <context id="DB2Tables" targetRuntime="MyBatis3">
        <!-- 数据库的连接信息 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
        connectionURL="jdbc:mysql://localhost:3306/mybatis"
        userId="root"
        password="123456">
        </jdbcConnection>
        <!-- javaBean的生成策略
        targetPackage:bean生成在哪个包
        targetProject:包生成在哪里-->
        <javaModelGenerator targetPackage="com.junqing.mybatis.bean"
        targetProject=".\src\main\java">
        <property name="enableSubPackages" value="true" /><!--是否自动生成包-->
        <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- SQL映射文件的生成策略 -->
        <sqlMapGenerator targetPackage="com.junqing.mybatis.mapper"
        targetProject=".\src\main\resources">
        <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>
        <!-- Mapper接口的生成策略 -->
        <javaClientGenerator type="XMLMAPPER"
        targetPackage="com.junqing.mybatis.mapper" targetProject=".\src\main\java">
        <property name="enableSubPackages" value="true" />
        </javaClientGenerator>
        <!-- 逆向分析的表 -->
        <!-- tableName:数据库中的表名-->
        <!-- domainObjectName:生成的实体类的类名 -->
        <!-- mapper接口和映射文件会根据domainObjectName自动生成 -->
        <table tableName="t_user" domainObjectName="User"/>
        </context>
</generatorConfiguration>

使用说明:

需要给pojo对象写一下有参、无参构造器和toString方法

(1)奢华尊享版查询所有数据

使用selectByExample方法,传进一个null即可

public void testMBG(){
    try {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = build.openSession(true);
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //selectByExample:表示根据条件查询,如果没有条件就表示查询所有数据
        List<User> users = mapper.selectByExample(null);
        for (User user:users){
            System.out.println(user);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

(2)奢华尊享版根据条件查询

  1. Example对象的createCriteria表示and,Example对象的or表示or
  2. createCriteria和or的方法都是以and打头的
  3. 一个Example对象是由若干createCriteria和or拼接起来的
public void testMBG(){
    try {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = build.openSession(true);
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        UserExample userExample = new UserExample();
        //createCriteria:表示and连接条件
        //or:表示or连接
        //userExample条件是所有的createCriteria和or连接起来的,他们的方法都是and打头的
        //例如下面的语句就是 password='123456' and username not null or username =yfj
        userExample.createCriteria().andPasswordEqualTo("123456").andUsernameIsNotNull();
        userExample.or().andUsernameEqualTo("yfj");
        List<User> users = mapper.selectByExample(userExample);
        for (User user:users){
            System.out.println(user);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

(3)奢华尊享版修改

updateByPrimaryKey:是根据主键修改(传进null,就修改成null

updateByPrimaryKeySelective:是根据主键选择性修改(如果传进null,就不会修改这个属性

其他方法也一样:带Selective的就是选择性修改,不带Selective的就是全部修改(传进null,就改成null)

(4)奢华尊享版添加

其他方法也一样:带Selective的就是选择性添加,不带Selective的就是全部添加(传进null,就改成null)

(5)奢华尊享版删除

其他方法也一样:带Selective的就是选择性删除,不带Selective的就是全部删除(传进null,就改成null)

十五、分页插件

不需要写sql语句,只需要设置相应的信息,就可以实现分页

可以通过分页插件获取所有的分页数据

例如:当前页的上一页,当前页的下一页,是不是最后一页,当前页是第几页,是不是最后一页

1.分页插件使用步骤

(1)添加依赖

<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
<dependency>
  <groupId>com.github.pagehelper</groupId>
  <artifactId>pagehelper</artifactId>
  <version>5.2.0</version>
</dependency>

(2)配置分页插件

在MyBatis的核心配置文件中配置(environments标签前面,typeAliases标签后面)

<plugins>
    <!--设置分页插件-->
    <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>

2.分页插件的使用

分页语句:limit index , pageSize

index:当前页的起始索引(pageNum-1)*pageSize

pageSize:每页显示的条数

pageNum:当前页的页码

使用MyBatis的分页插件实现分页功能:

  1. 需要在查询功能直线开启分页

    PageHelper.startPage(当前页码,每页的条数)

  2. 在查询功能之后获取分页相关信息

    PageInfo page=new PageInfo(users,5);

(1)开启分页功能

只需要在查询语句之前开启分页功能:PageHelper.startPage(当前页码,每页的条数)

InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = build.openSession(true);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
PageHelper.startPage(1,4);//表示开启分页,第一个参数是当前页码,第二个参数是页面展示数据条数
UserExample userExample = new UserExample();
userExample.createCriteria().andPasswordEqualTo("123456").andUsernameIsNotNull();
userExample.or().andUsernameEqualTo("yfj");
List<User> users = mapper.selectByExample(userExample);
for (User user:users){
    System.out.println(user);
}

(2)获取分页相关数据

在查询获取list集合之后,使用PageInfo<集合存放的数据类型> pageInfo = new PageInfo<>(List list, int navigatePages)获取分页相关数据

list:分页之后的数据

navigatePages:导航分页的页码数

InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = build.openSession(true);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
PageHelper.startPage(2,5);//开启分页
UserExample userExample = new UserExample();
userExample.createCriteria().andPasswordEqualTo("123456").andUsernameIsNotNull();
userExample.or().andUsernameEqualTo("yfj");
List<User> users = mapper.selectByExample(userExample);
//PageInfo中的泛型是List中存放的类型
//参数:第一个是查询到的集合,第二个是展示的页码个数(类似于页面中展示的当前页面,和当前页面左右两边的页码)
PageInfo<User> page=new PageInfo<User>(users,5);
for (User user:users){
    System.out.println(user);
}

(3)分页相关数据

PageInfo{

pageNum=8, pageSize=4, size=2, startRow=29, endRow=30, total=30, pages=8, list=Page{count=true, pageNum=8, pageSize=4, startRow=28, endRow=32, total=30, pages=8, reasonable=false, pageSizeZero=false}, prePage=7, nextPage=0, isFirstPage=false, isLastPage=true, hasPreviousPage=true, hasNextPage=false, navigatePages=5, navigateFirstPage4, navigateLastPage8, navigatepageNums=[4, 5, 6, 7, 8]

}

常用数据:

pageNum:当前页的页码

pageSize:每页显示的条数

size:当前页显示的真实条数

total:总记录数

pages:总页数

prePage:上一页的页码

nextPage:下一页的页码

isFirstPage/isLastPage:是否为第一页/最后一页

hasPreviousPage/hasNextPage:是否存在上一页/下一页

navigatePages:导航分页的页码数

navigatepageNums:导航分页的页码,[1,2,3,4,5]

十六、MyBatis快速总结

1.MyBatis的基本说明

1.核心配置文件用来存放数据库的url、username、password等信息,还存放映射文件的包路径。核心配置文件一般放在resources下,springboot中可以没有【因为都放在yaml文件中了】

2.在核心配置文件的mappers标签中使用package标签批量引入映射文件的时候,映射文件需要在reousrces下,包名需要和mapper接口的包路径一致

3.映射文件类似于原来的DaoImpl(mapper标签的namespace属性就是Mapper接口的全路径,增删改查都有对应的标签(标签的id属性就是接口中的方法名))

4.Mapper接口【需要加@Mapper注解】对应着原来的Dao,里面只定义方法,具体操作在映射文件中写

5.查询标签使用的时候需要确定查询出来的数据转化为什么类型,因此要设置resultType或者resultMap属性从而说明结果类型(值是对应类型的全路径)

6.resulType是默认的映射关系(查询出来的结果可以直接放到结果类型里面),resultMap是自定义映射类型(字段名和bean属性不一样的时候使用)

2.映射文件获取值的方法

映射文件获取参数的两种方式:${ }和#{ }

  1. ${ }:就是字符串拼接,所以存在SQL注入,所以使用的时候外面需要单引号【有些查询必须使用这个,例如:批量删除、动态设置表名、获取自增主键,具体看笔记】
  2. #{ }:就是占位符赋值,会自动加单引号
  3. 如果只传入一个参数,那么直接把参数名添加到sql中即可
  4. 如果传入的参数有多个,myabtis会自动封装到Map中,那么需要以arg0,arg1 … 或者 param0,param1 … 为键
  5. 因此如果有多个参数传入,我们可以手动将参数封装的到Map中,那么传入参数的时候,可以使用自己设置的键
  6. 如果传入的是一个实体类对象,那么获取参数的值是set和get方法名去掉set或者get后剩下的名字
  7. 如果mapper接口方法中的参数使用@Param注解,那么获取参数的时候就是Param注解的值【@Param可以自定义键名】
  8. 因此可以分为两种情况获取参数(上面几种都可以用,但是建议):如果传入的实体对象,直接使用去掉set后的名字,其他的使用@Param注解

3.查询结果

  1. 如果查询出的数据只有一条(行),可以通过实体类或者List集合接收

  2. 如果查询出的数据有多条,只能通过List集合接收,resultType的值还是单条数据的类型

    例如:每一行可以封装到User类中,那么resultType的值就是User

  3. 如果查询出来的数据是单行单列的值,可以不用实体类接收,可以用java中常用的数据类型接收(如:int,String,List等),resultType中可以不用写全路径,直接用平时的写法就行

    例如:int,String,BigDecimal,List,Map等

4.模糊查询的方法

模糊匹配有很多方法,可以使用${ }。但是最推荐的是用双引号把匹配符号引起来,然后使用#{ }

<!--例如:-->
select * from emp where username like "%"#{username}"%"

5.获取自动增长的主键

insert标签中有一个useGeneratedKeys属性设置为true,然后keyProperty属性设置需要将主键的值给哪个属性

keyProperty:将自增的主键的值赋给resultType中的哪个属性中

<!--例如:将数据插入到emp表,emp表的主键是id。要求插入完成后还需要获取主键-->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
	insert into emp values(null,#{username},#{age})
</insert>

6.解决sql字段和Bean的属性名不一致的方法(三种)

  • 方法一:查询的sql语句为sql字段设置别名

    select empname name ,emp_age age from emp
    
  • 方法二:通过全局配置文件设置驼峰映射(mapUnderscoreToCamelCase属性),SpringBoot中也是这样

  • 方法三:通过resultMap设置自定义映射关系

    1. 首先外面使用resultMap标签,标签的id属性随便,type属性是每一行查询结果对应的实体类

    2. 然后resultMap标签里面使用id标签设置主键映射关系,id标签中的property是实体类中的属性名,column是SQL中对应的列名

    3. result标签用来设置普通属性的映射,property是实体类中的属性名,column是SQL中对应的列名

    4. 最后select标签的resultMap属性的值就是外面自定义的resultMap标签的id值

    <resultMap id="empResultMap" type="Emp">
    	<id property="eid" column="id"></id>
    	<result property="empName" column="emp_name"></result>
    	<result property="empAge" column="emp_age"></result>
    	<result property="empTall" column="emp_tall"></result>
    </resultMap>
    
    <select id="getAllEmp" resultMap="empResultMap">
    	select * from emp
    </select>
    

7.处理多对一映射关系的方法(三种)

多对一关系只需要在一的实体类中设置多的集合,在多的实体类中设置一的属性。

【例如:学生与班级,在学生类中添加班级对象,在班级类中添加学生集合】

  • 方式一:使用resultMap级联赋值

  • 方式二:在resultMap中使用association标签设置

  • 方式三:分步查询,多个SQL查询出最终结果(以后使用最多的方式)

    也是使用association标签,设置property(属性名)、select(第二条select语句的全路径.id)、column(子查询的条件)属性

​ 例如:先查询出员工的部门id,然后根据部门id查询部门信息

【员工查询的xml中使用resultMap,设置相关字段,然后里面使用association设置下一个sql的信息(property【实体类中的对象属性】、select【下一个sql的全路径.id】、column【子查询的条件】)】

<resultMap id="empResultMap" type="Emp">
	<id property="eid" column="id"></id>
	<result property="empName" column="emp_name"></result>
	<result property="empAge" column="emp_age"></result>
	<association property="dept" select="com.junqing.mapper.getDept" column="deptId">
</resultMap>

<select id="getAllEmp" resultMap="empResultMap">
	select * from emp where emp_name= #{name}
</select>

8.分步查询开启懒加载的注意事项

  1. 延迟加载会根据访问的数据确定是否加载下一个sql信息

    例如:访问员工信息,就不会去加载查询部门的sql,访问部门信息,就会加载查询部门的子sql

  2. association中的fetchType属性可以在开启延迟加载之后手动控制延迟加载的效果

    lazy标识延迟加载,eager表示立即加载

9.处理一对多映射关系的方法(两种)

  1. 使用resultMap和collection(使用方法和association基本一样)

    在resultMap标签中使用使用collection标签,设置property(属性名)、ofType(集合中存的实体类)属性,然后在里面设置集合中寸的实体类的映射关系

  2. 分步查询【和使用association的方法一样,只不过换成了collection】

10.动态SQL

10.1 if标签

if标签,可以根据条件判断是否将里面的语句拼接到需要执行的SQL中,只有test属性,用来写判断条件【如果test中有多个条件,直接使用and/or拼接】,判断完之后使用or或者and拼接sql

说明:if标签用在where字段后面,所以建议where后面加一个条件1=1,防止第一个if标签里面的条件不成里【可以使用where标签解决这个问题】

<select id="query" resultType="com.sky.entity.ShoppingCart">
    	select * from  shopping_cart
        		<if test="dishId!=null and dishId!=''">
            		user_id=#{userId}
        		</if>
        		<if test="dishId!=null and dishId!=''">
            		and dish_id=#{dishId}
        		</if>
        		<if test="setmealId!=null and setmealId!=''">
            		and setmeal_id=#{setmealId}
        		</if>
        		<if test="dishFlavor!=null and dishFlavor!=''">
           			and  dish_flavor=#{dishFlavor}
        		</if>
	</select>

10.2 where标签

where标签会自动生成where关键字并且将内容前多余的and 或 or 去掉【只能去掉内容前的多余and和or,不能去掉内容后的and和or】,所以可以把if标签放在where标签里面,如果where标签里面没有任何内容,那么where关键字不会起作用

<select id="query" resultType="com.sky.entity.Employee">
	select * from employee
	<where>
		<if test="name != null and name != ''">
			and name like concat('%',#{name},'%')
        </if>
    </where>
</select>

10.3 foreach标签

foreach标签用来实现批量删除和批量添加功能【将集合或者数组中的数据遍历出来,放到sql中】

foreach的属性:

collection:就是传进来的数组名

item:表示数组或集合中的每一个元素,如果是一个对象,那么可以用对象.属性(随便起个名字,只要#{}里面用他就行)

separator:表示分隔符

open:表示foreach以什么开始

close==属性:表示foreach以什么结束

接口方法:int deleteUser(@Param("usernames")Integer[] usernames);
//因为是数组所以会放到Map中以argX访问,使用Param自定义访问方式(不然下面的collection属性会访问不到数据)

<delete id="deleteUser">
	delete from t_user where username in
    	<foreach collection="usernames" item="username" separator=","  open="(" close=")">
       		 #{username}
   	    </foreach>
</delete>
接口方法:void insert(List<OrderDetail> orderDetails);
<insert id="insert">
    	insert into order_detail (name,image,order_id,dish_id,setmeal_id,dish_flavor,number,amount) values
    	<foreach collection="orderDetails" item="orderDetail" separator=",">
        (#{orderDetail.name},#{orderDetail.image},#{orderDetail.orderId},#{orderDetail.dishId},#{orderDetail.setmealId},#{orderDetail.dishFlavor},#{orderDetail.number},#{orderDetail.amount})
    	</foreach>
</insert>

11.MyBatis的缓存

11.1 MyBatis的一级缓存

  • 一级缓存默认开启,默认是sqlSession级别的(只对当前会话有效),缓存只针对于查询有效。同一个SqlSession查询的数据会被缓存,下次查询相同的数据就会直接从缓存中获取,不再访问数据库
  • 一级缓存失效的四种情况:
    1. 使用不同的sqlSession
    2. 使用同一个sqlSession但是查询条件不同
    3. 使用同一个sqlSession,但是两次查询中间执行了任意一次增删改操作
    4. 使用同一个sqlSession,但是两次查询中间手动清空了缓存(sqlsession的clearCache方法)

11.2 MyBatis的二级缓存

  1. 二级缓存是SqlSessionFactory级别的,二级缓存需要手动开启
  2. 开启二级缓存的方法看上面的详细笔记
  3. 二级缓存必须在SQLSession关闭或提交之后有效(SqlSession的commit或者close方法),同时查询结果所转化的实体类必须可以序列化(实现了Serializable接口)
  4. 增删改可以使一级、二级缓存同时刷新

11.3 MyBatis的缓存查询问题

  1. 先查询二级缓存(因为范围大),如果没有再查询一级缓存,如果一级缓存还没有则查询数据库。

  2. SqlSession关闭之后,一级缓存中的数据会缓存到二级缓存中

12.分页插件PageHelper的使用

  1. 引入依赖,就可以直接在Service中使用
  2. Service的方法中设置分页参数:PageHelper.startPage需要两个参数分别是当前查询页码,页面大小
  3. 然后调用Mapper方法(要求Mapper方法返回的对象是Page类型的对象)
  4. 最后从Page对象中过去需要的信息(如:总记录数、当前页数据等)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
MyBatis是一个开源的持久化框架,可以帮助我们将数据从数据库中读取出来,然后转换为Java对象,并将Java对象写入数据库中。 在C#中使用MyBatis,需要先安装MyBatis.Net库,然后在项目中引用该库。接着,我们需要创建一个配置文件,用于配置MyBatis的数据库连接信息、SQL语句等。在配置文件中,我们需要指定一个别名,用于在程序中引用这个配置文件。 接下来,我们需要创建一个映射文件,用于将数据库中的数据映射为Java对象。在映射文件中,我们需要定义一个 resultMap,用于定义Java对象与数据库表之间的关系。我们还需要定义一个 SQL 语句,用于从数据库中读取数据,并将其转换为Java对象。 在程序中,我们需要创建一个 SqlSession 对象,用于执行SQL语句。我们可以通过SqlSession对象调用selectOne、selectList、update、delete等方法,来执行SQL语句,并将结果转换为Java对象或者操作数据库。 下面是一个简单的示例,展示了如何在C#中使用MyBatis: 1. 安装MyBatis.Net库 在Visual Studio中,选择“工具”-“NuGet包管理器”-“程序包管理器控制台”,然后输入以下命令: ``` Install-Package MyBatisNet ``` 2. 创建配置文件 在项目中创建一个名为“SqlMapConfig.xml”的文件,用于配置数据库连接信息、SQL语句等。以下是一个示例配置文件: ``` xml <?xml version="1.0" encoding="utf-8" ?> <sqlMapConfig> <database> <provider name="SqlServer" connectionString="Data Source=localhost;Initial Catalog=mydatabase;User ID=myuser;Password=mypassword;" /> </database> <sqlMap> <map resource="MyMapper.xml"/> </sqlMap> </sqlMapConfig> ``` 其中,provider元素用于指定数据库类型和连接字符串,map元素用于指定映射文件路径。 3. 创建映射文件 在项目中创建一个名为“MyMapper.xml”的文件,用于将数据库中的数据映射为Java对象。以下是一个示例映射文件: ``` xml <?xml version="1.0" encoding="utf-8" ?> <sqlMap namespace="MyMapper"> <resultMap id="MyResultMap" class="MyClass"> <result property="id" column="id"/> <result property="name" column="name"/> </resultMap> <select id="selectById" resultMap="MyResultMap"> SELECT * FROM mytable WHERE id=#id# </select> </sqlMap> ``` 其中,resultMap元素用于定义Java对象与数据库表之间的关系,select元素用于定义SQL语句。 4. 在程序中使用MyBatis 在程序中,我们需要创建一个 SqlSession 对象,用于执行SQL语句。以下是一个示例代码: ``` csharp using IBatisNet.DataMapper; using IBatisNet.DataMapper.Configuration; using IBatisNet.DataMapper.Configuration.Files; // 创建配置文件 DomSqlMapBuilder builder = new DomSqlMapBuilder(); ISqlMapper sqlMapper = builder.Configure(@"SqlMapConfig.xml"); // 执行SQL语句 MyClass obj = sqlMapper.QueryForObject<MyClass>("MyMapper.selectById", new { id = 1 }); ``` 以上是一个简单的示例,展示了如何在C#中使用MyBatis。实际上,MyBatis还有很多其他的用法和功能,需要我们在实际开发中去探索和使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值