Mybatis

 

第一章:MyBatis简介

第一节:MyBatis的特点

  1. 一个基于Java的持久层(数据的长久保存-DB)框架,解决应用程序和数据库之间进行数据交互的框架(jdbc)。前身是 apache的一个开源项目iBatis
  2. iBatis 提供的持久层框架 包括SQL MapsData Access ObjectsDAOs),执行CRUD操作(增加(Create)、读取查询(Read)、更新(Update)和删除(Delete)
  3. MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
  4. MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java  POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。
  5. MyBatis框架也被称之为ORMObject/Relation Mapping,即对象关系映射)框架。所谓的ORM就是一种为了解决面向对象与关系型数据库中数据类型不匹配的技术,它通过描述Java对象与数据库表之间的映射关系,自动将Java应用程序中的对象持久化到关系型数据库的表中。 

 

第二节:MyBatis的工作原理

 

 

第二章:Maven安装及配置(Idea

 

第三章:使用Maven搭建MyBatis项目

  1. 使用步骤

1) pom.xml 中添加mybatis的依赖项

<properties>

        <mybatis.version>3.4.4</mybatis.version>

        <mysqlconn.version>8.0.17</mysqlconn.version>

    </properties>

    <dependencies>

        <!-- log4j 日志 -->

        <dependency>

            <groupId>log4j</groupId>

            <artifactId>log4j</artifactId>

            <version>1.2.17</version>

        </dependency>

        <!-- junit -->

        <dependency>

            <groupId>junit</groupId>

            <artifactId>junit</artifactId>

            <version>4.12</version>

            <scope>test</scope>

        </dependency>

        <dependency>

            <groupId>org.mybatis</groupId>

            <artifactId>mybatis</artifactId>

            <version>${mybatis.version}</version>

        </dependency>

        <dependency>

            <groupId>mysql</groupId>

            <artifactId>mysql-connector-java</artifactId>

            <version>${mysqlconn.version}</version>

        </dependency>

    </dependencies>

 

2) resource文件夹下,创建db.properties 配置文件,设置数据库连接相关字符串属性,

mysql.driver=com.mysql.cj.jdbc.Driver

mysql.dburl=jdbc:mysql://127.0.0.1:3306/db_book?userSSL=true&useUnicode=true&characterEncoding=UTF8&serverTimezone=GMT

mysql.loginname=root

mysql.loginpass=root

 

3) resource文件夹下,创建MyBatis的配置文件 *.xml

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE configuration   PUBLIC "-//mybatis.org//DTD Config 3.0//EN"   "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

    <!-- 添加数据库属性配置文件 -->

    <properties resource="db.properties" />

    <!-- 懒加载设置 -->

    <settings>

        <!-- 打开延迟加载的开关 -->

        <setting name="lazyLoadingEnabled" value="true" />

        <!-- 将积极加载改为消息加载即按需加载 -->

        <setting name="aggressiveLazyLoading" value="false"/>

    </settings>

    <!--

      <typeAliases>

          <package name="com.rounding.entity"/>

      </typeAliases>

      -->

    <!-- 配置数据库连接 -->

    <environments default="development">

        <environment id="development">

            <transactionManager type="JDBC"/>

            <dataSource type="POOLED">   <!-- UNPOOLED 只在每次请时打开和关闭一个连接;POOLED 缓存JDBC连接对象;JDNI Spring时使用 -->

                <property name="driver" value="${mysql.driver}"/>

                <property name="url" value="${mysql.dburl}"/>

                <property name="username" value="${mysql.loginname}"/>

                <property name="password" value="${mysql.loginpass}"/>

            </dataSource>

        </environment>

    </environments>

   <mappers>

        <mapper resource="com/isoft/mapper/SysMapper.xml"/>

    </mappers>

</configuration>

 

4) 添加log4j 的属性文件log4j.properties

log4j.rootLogger=DEBUG, Console
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

 

 

5) 创建数据库CRUD操作所需要的接口文件

public interface TestDao {
    int add(Test t);
}

 

 

6) 创建*.xml 映射文件,描述接口中所需要实现的方法依赖的sql语句以及该方法返回值类型(select),或者在接口的抽象方法上方注解该方法实现所依赖的sql语句。

减价
 <insert id="add">
     insert into book values(null,'test',90.4,90)
 </insert>
</mapper>

 

 

7) MyBatis的配置文件的<mapper>下添加资源映射文件所在文件或者注解文件所在位置

<mappers>
    <mapper resource="com/iss/mapper/BookDaoMapper.xml"/>
</mappers>

 

 

8) 数据库操作实现(insertupdatedelete需要commit

9) Test类:

import dao.TestDao;
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;


public class Test {
    @org.junit.Test
    public void test(){
        try {
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml"));
            SqlSession sqlSession = factory.openSession();
            System.out.println(sqlSession);
            TestDao dao = sqlSession.getMapper(TestDao.class);
            Integer count = dao.add(null);
            System.out.println("count="+count);
            sqlSession.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

 

第四章:MyBatis基本使用

  1. 实体类规则

1) 实现序列号接口

2) 必须包括空构造方法

3) 含有私有属性

4) 含有getset方法组

5) 含有toString方法

  1. 使用@Test测试
  2. openSession()表示不默认提交事务,增删改需要sqlSession.commit()方法进行提交。openSessiontrue)表示,默认提交事务
  3. insertupdatedelete返回的是整数,含义是受影响的行数,在xml文件中不用声明返回值类型。
  4. mysql主键自增长的使用:两种解决办法

1) 实体类设计id字段为Integer类型,id的值设为null,如

<insert id="addType" parameterType="pojo.Type">
    insert into book_type values(#{tId},#{tName})
</insert>

int id = typeDao.addType(new Type(null,"自然科学类"));

2) 插入时在sql语句中,指定插入字段

insert into book (b_name,b_author,b_type,b_publisher,b_adddate) values(#{name},#{authorId},#{typeId},#{publisherId},#{addDate})

  1. Sql标签

select <include refid="BaseColumns"></include>
from sys_user

 

  1. parameterTypexml中,传入数据的类型,可省略
  2. ResultType:描述的是返回值类型所对应的java类型,可以是intString,也可以是一个对象类型Book,但是必须应用在数据库字段名,和实体类属性名一致的情况,才可以自动将字段的值注入到实体类中属性值里。

intINTEGERjava.lang.Integer都可以)(Stringjava.lang.String

https://blog.csdn.net/lv4961382/article/details/89445344

<select id="getCount" resultType="int">

        select count(*) from tb_sys

    </select>

  1. ResultMapjava中实体类成员变量名与数据库中表的字段名不一致时,通过ResultMap来解决,ResultMap中的javaTypejdbcType可以省略,如果不省略,jdbcType里的数据库类型必须用全大写字母表示,比如INTEGERVARCHAR

<resultMap id="BaseResultMap" type="pojo.Book">
    <id column="b_id" property="id" javaType="Integer" jdbcType="INTEGER"></id>
    <result column="b_name" property="name" javaType="String" jdbcType="VARCHAR"></result>
    <result column="b_type" property="typeId" ></result>
    <result column="b_author" property="authorId"></result>
    <result column="b_publisher" property="publisherId"></result>
    <result column="b_addDate" property="addDate"></result>
</resultMap>

  1. 接口中方法多个参数映射到xml文件时,需要加@Param

List<Book> selectBookByNameAndAuthorId(@Param("name") String name,@Param("authorId") int authorId);

  1. Limit 的使用

List<Book> getPageData(@Param("bookName") String bookName,@Param("offset") Integer offset,@Param("rows") Integer rows);

 

<select id="getPageData" resultMap="BookResultMap">
    select * from book
    <where>
    <if test="bookName != null and bookName!=''">
    <bind name = "bname" value="'%'+bookName+'%'"/>

    and b_name like #{bname}

    </if>
    </where>
    limit #{offset},#{rows}
</select>

 

  1. 大于号和小于号要使用符号实体

<select id="selectBookByPrice"  resultMap="BaseResultMap">
    select
    <include refid="BaseColumnList"></include>
    from book
    where b_price >=#{min} and b_price <=#{max}
</select>

 

 

  1. 一对一的关系的查询:两种实现方式

1) 两表内连接,设置一个新实体类,将两个表的属性放在一个实体类中,xml文件中写resultMap映射两个表的属性,新写daomapperTest类测试,mapper中的select语句,用inner join或者where连接

2) 通过association实现:

注意<association property="userInfo" javaType="pojo.UserInfo">
中必须加javaType,不然会报空指针错误

如果报构造方法找不到的错误,是因为没有给从表的实体类加空的构造方法

<resultMap id="BaseResultMap" type="pojo.User">
    <id column="u_id" property="u_id" javaType="Integer" jdbcType="INTEGER"></id>
    <result column="u_name" property="u_name" javaType="String" jdbcType="VARCHAR"></result>
    <result column="u_pwd" property="u_pwd"></result>
    <result column="u_role_id" property="u_role_id"></result>
    <association property="userInfo" javaType="pojo.UserInfo">

        <result column="u_gender" property="u_gender"></result>
        <result column="u_user_id" property="u_user_id"></result>
    <result column="u_adddate" property="u_adddate"></result>
    </association>
</resultMap>

Sql语句:

<sql id="BaseColumns">
   sys_user.u_id,u_name,u_pwd,u_role_id,u_user_id,u_gender,u_adddate
</sql>
<select id="selectUserById" resultMap="BaseResultMap">
select <include refid="BaseColumns"></include>
from sys_user inner join user_info on sys_user.u_id=user_info.u_user_id
where sys_user.u_id=#{id};
</select>

实体类:

ublic class User{
    private int u_id;
    private String u_name;
    private String u_pwd;
    private int u_role_id;
    private UserInfo userInfo;--从表的属性

 

  1. 一对一的关系的插入:引入service

Service

public class UserService {
    private UserDao userDao;
    private UserInfoDao userInfoDao;
    private SqlSession sqlSession;

    public UserService(SqlSession sqlSession) {
        this.sqlSession = sqlSession;
        userDao = sqlSession.getMapper(UserDao.class);
        userInfoDao = sqlSession.getMapper(UserInfoDao.class);
    }

    public boolean add(User user) {
        int count = userDao.add(user);
        if (count > 0) {
            //通过用户名和密码查询新添加的信息的id
            Integer id = userDao.selectId(user.getU_name(), user.getU_pwd());
            if (id != null){
                UserInfo userInfo = user.getUserInfo();
                userInfo.setU_user_id(id);
                int t = userInfoDao.add(userInfo);
                if (t > 0) {
                    return true;
                }
            }
        }
        return false;
    }

    public SqlSession getSqlSession() {
        return sqlSession;
    }

    public void setSqlSession(SqlSession sqlSession) {
        this.sqlSession = sqlSession;
    }
}

Test

public class UserDaoTest {

    @Test
    public void test() {
        SqlSession sqlSession = null;
        try {
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-conf.xml"));
            sqlSession = factory.openSession();
            //添加用户:一对一关系
            UserService service = new UserService(sqlSession);
            UserInfo userInfo = new UserInfo(null,null,"", TimeUtil.getFormatTime(new Date()));
            User user = new User(null,"test1","123",1,userInfo);
            if(service.add(user)){
                sqlSession.commit();
            };
          
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally {
            if(sqlSession != null){
                sqlSession.close();
                sqlSession = null;
            }
        }
    }
}

 

  1. 一对多的关系注意,两个表的id列不能取相同的名字,这样会只显示一条数据

1) 方法一:多表联查,新建实体

2) 使用collection

<resultMap id="BaseResultMapWithBook" type="pojo.Type">
    <id column="t_id" property="tId"></id>
    <result column="t_name" property="tName"></result>
    <collection property="list" ofType="pojo.Book">
        <id column="b_id" property="id" javaType="Integer" jdbcType="INTEGER"></id>
        <result column="b_name" property="name" javaType="String" jdbcType="VARCHAR"></result>
        <result column="b_type" property="typeId"></result>
        <result column="b_author" property="authorId"></result>
        <result column="b_publisher" property="publisherId"></result>
        <result column="b_addDate" property="addDate"></result>
    </collection>
</resultMap>

 

<select id="selectAllBookWithType" resultMap="BaseResultMapWithBook">
    select t_id,t_name,b_id,b_name,b_author,b_type,b_publisher,b_adddate from book_type inner  join book
    on t_id=b_type
</select>

实体类:

private Integer tId;
private String tName;
private List<Book> list;

结果:

 

3) 使用多条sql语句执行:根据图书种类查询该类别下的所有图书

Type selectBooksByTypeName(String name);

BookMapper中的通过typeid查询该类别下的所有图书

<select id="selectBookWithTypeId" resultMap="BaseResultMap">
    select * from book where b_type=#{typeid}
</select>

TypeMapper下的多条sql查询:

<select id="selectBooksByTypeName" resultMap="BaseResultMap2">
    select t_id,t_name from book_type where t_name=#{name}
</select>
<resultMap id="BaseResultMap2" type="pojo.Type">
    <id column="t_id" property="tId"></id>
    <result column="t_name" property="tName"></result>
    <collection property="list" ofType="pojo.Book" select="dao.BookDao.selectBookWithTypeId" column="t_id"></collection>
</resultMap>

4) 多对一同样使用方法:多条sql

查询每本图书信息,包括其类别信息

<resultMap id="BaseResultMap2" type="pojo.Book">
    <id column="b_id" property="id" javaType="Integer" jdbcType="INTEGER"></id>
    <result column="b_name" property="name" javaType="String" jdbcType="VARCHAR"></result>
    <result column="b_type" property="typeId"></result>
    <result column="b_author" property="authorId"></result>
    <result column="b_publisher" property="publisherId"></result>
    <result column="b_addDate" property="addDate"></result>
    <association property="type" select="dao.TypeDao.selectById" column="b_type"></association>
</resultMap>

  1. Mybatis别名:

mybatis的配置的xml文件中,增加别名属性:

可以为每个单独的类声明别名,也可以为整个实体类包声明别名

1) 为整个实体类包声明别名,申明之后Mapperxml文件中只写类名,就不用写包名了:

<typeAliases>
    <package name="com.rounding.entity"/>
</typeAliases>

2) 为每个类声明别名:

<typeAliases>
    <typeAlias type="pojo.Book" alias="book"></typeAlias>
</typeAliases>

使用方法:

<resultMap id="BaseResultMap2" type="book">

  1. $#的区别:#是转换成数据类型,$原封不动的把字符串放进去,不加数据类型,所以是字段,注意事项:参数必须加@Param声明

//   按照图书的制定字段顺序升序显示,$#的区别
    List<Book> getAllBookByOrder(@Param("orderBy") String orderBy);

 

<select id="getAllBookByOrder" resultMap="BaseResultMap">
    select * from book order by ${orderBy} desc
</select>

 

  1. SqlSession的封装

ublic class SqlSessionUtil {
    private static SqlSessionUtil ourInstance;
    private static SqlSession sqlSession;
    private static String configFile = null;

    // 私有构造方法
    private SqlSessionUtil() {

    }
    public synchronized static SqlSessionUtil getInstance(String configFile) {
        if (configFile != null && configFile.trim().length() > 0) {
            SqlSessionUtil.configFile = configFile;
        } else {
            SqlSessionUtil.configFile = "mybatis-config.xml";
        }
        if (ourInstance == null ) {
            ourInstance = new SqlSessionUtil();
        }

        return ourInstance;
    }



    public SqlSession getSqlSession() {
        if (sqlSession == null) {
            try {
                sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader(configFile)).openSession();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sqlSession;
    }

    public void closeSqlSession() {
        if (sqlSession != null) {
            sqlSession.close();
            sqlSession = null;
        }
    }
}

多次调用,打印的结果:

SqlSession sqlSession1 = SqlSessionUtil.getInstance("mybatis-conf.xml").getSqlSession();
        System.out.println("1="+SqlSessionUtil.getInstance("mybatis-conf.xml")+","+sqlSession1);
//        BookDao bookDao = sqlSession1.getMapper(BookDao.class);
//        List<Book> list = bookDao.selectAllWithType();
//        for(Book b: list){
//            System.out.println(b);
//        }
        SqlSessionUtil.getInstance("mybatis-conf.xml").closeSqlSession();
        SqlSession sqlSession2 = SqlSessionUtil.getInstance("mybatis-conf.xml").getSqlSession();
        System.out.println("2="+SqlSessionUtil.getInstance("mybatis-conf.xml")+","+sqlSession2);

 

 

第四章:动态sql应用

  1. 动态sqlsql语句描述时,支持判定等逻辑处理
  2. bind:用于绑定数据,一般用于模糊查询

注意:使用bind时,dao接口方法的参数必须要加@Param说明(即使只有一个参数),如:

List<Book> selectBookByName(@Param("name") String name);

mapper.xml

<select id="selectBookByName" resultMap="BaseResultMap">
        <bind name="bname" value="'%'+name+'%'"/>
    select
    <include refid="BaseColumns"></include>
    from book where b_name like #{bname};
</select>

 

  1. if:单分支

例:模糊查询,查询含有字符的图书,如果为空,都查询

<if test="name!=null">
    <bind name="bname" value="'%'+name+'%'"/>
</if>

<if test="name==null">
    <bind name="bname" value="'%'"/>
</if>
select
<include refid="BaseColumns"></include>
from book where b_name like #{bname};

  1. where:可以去掉多余的andor或者where

例:按照图书姓名或者图书简介,作者添加时间进行模糊查询,传入多个参数

List<Book> selectByMore(@Param("name") String name,@Param("date") String date,@Param("desc") String desc);

 

<select id="selectByMore" resultMap="BaseResultMap">
    select <include refid="BaseColumns"></include>
    from book
    <where>
        <if test="name !=null and name!=''">
        <bind name="sName" value="'%'+name+'%'"></bind>
            and b_name like #{sName}
        </if>
        <if test="date !=null and date!=''">
            <bind name="sDate" value="'%'+date+'%'"></bind>
            and b_adddate like #{sDate}
        </if>
        <if test="desc !=null and desc!=''">
            <bind name="sDesc" value="'%'+desc+'%'"></bind>
            and b_desc like #{sDesc}
        </if>
    </where>
</select>

 

  1. set:用来设置updateset部分,可以去掉多余的逗号

<update id="updateBook" parameterType="pojo.Book">
    update book
    <set>
        <if test="name != null and name!=''">
            b_name = #{name},
        </if>
        <if test="authorId != null and authorId!=''">
            b_author = #{authorId},
        </if>
        <if test="publisherId != null and publisherId!=''">
            b_publisher = #{publisherId},
        </if>
        <if test="typeId != null and typeId!=''">
            b_type = #{publisherId},
        </if>
        <if test="addDate != null and addDate!=''">
            b_adddate = #{publisherId},
        </if>
        <if test="desc != null and desc!=''">
            b_desc = #{desc},
        </if>
    </set>
    where b_id = #{id}
</update>

  1. trim:可以替换where或者set,添加前缀,或者后缀,添加前面覆盖字符,或者后面覆盖字符

<update id="updateBook2" parameterType="pojo.Book">
    update book
    <trim prefix="set" suffixOverrides=",">
        <if test="name != null and name!=''">
            b_name = #{name},
        </if>
        <if test="authorId != null and authorId!=''">
            b_author = #{authorId},
        </if>
        <if test="publisherId != null and publisherId!=''">
            b_publisher = #{publisherId},
        </if>
        <if test="typeId != null and typeId!=''">
            b_type = #{publisherId},
        </if>
        <if test="addDate != null and addDate!=''">
            b_adddate = #{publisherId},
        </if>
        <if test="desc != null and desc!=''">
            b_desc = #{desc},
        </if>
    </trim>
    where b_id = #{id}
</update>

 

  1. foreach批量删除

//批量删除,用到foreach
int deleteMore(Integer[] ids);

<delete id="deleteMore" >
    delete from book where b_id in
    <foreach collection="array" item="id" separator="," open="(" close=")">
        #{id}
    </foreach>
</delete>

 

  1. choose-when多分支
  2. 符号实体,大于号和小于号需要用><
  3. 通俗的讲就是按需加载,我们需要什么的时候再去进行什么操作。而且先从单表查询,需要时再从关联表去关联查询,能大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
  4. mybatis中,resultMap可以实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具备延迟加载功能。只有使用association、collection时,才有懒加载概念。

第五章:MyBatis懒加载

1) 懒加载实现:在mybatis-config文件中设置开启懒加载模式

<settings>
    <!-- 打开延迟加载的开关 -->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!-- 将积极加载改为消息加载即按需加载 -->
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

 

2) 比如,需要查询图书种类和每个种类中的图书列表

代码:

<resultMap id="BaseResultMap2" type="pojo.Type">
    <id column="t_id" property="tId"></id>
    <result column="t_name" property="tName"></result>
    <collection property="list" ofType="pojo.Book" select="dao.BookDao.selectBookWithTypeId" column="t_id"></collection>
</resultMap>

 

<select id="selectBooksByTypeName" resultMap="BaseResultMap2">
    select t_id,t_name from book_type where t_name=#{name}
</select>

不开启懒加载时,如果只查主表的信息时,会进行子表的查询:

Integer t_id = dao.selectBooksByTypeName("文学类").gettId();
System.out.println(t_id);

 

结果为:

 

开启懒加载时:如果只查主表的信息时,不会进行子表的查询:

结果为:

 

懒加载模式,只要需要查询子表相关信息时,才会进行子表查询

 

章:注解方式

第一节: @ResultMap:使用步骤

  1. @ResultMap:使用步骤

1) 新建一个xml文件,专门写所有的ResultMapnamespace对象的是在java注解中对应的包路径

<mapper namespace="com.mapper.ResultMap">
    <resultMap id="BookResultMap" type="pojo.Book">
        <id column="b_id" property="id" javaType="Integer" jdbcType="INTEGER"></id>
        <result column="b_name" property="name" javaType="String" jdbcType="VARCHAR"></result>
        <result column="b_type" property="typeId"></result>
        <result column="b_author" property="authorId"></result>
        <result column="b_publisher" property="publisherId"></result>
        <result column="b_addDate" property="addDate"></result>
        <result column="b_desc" property="desc"></result>
    </resultMap>
</mapper>

 

2) mybatis的配置文件中,配置ResultMaps文件和Dao类,注意Resultmapxml文件要放在class文件之上,不然会报“Mapped Statements collection already contains value for com.XXXX”的错误

<mappers>

<!--注意先后顺序-—>
    <mapper resource="com/mapper/ResultMaps.xml"></mapper>
    <mapper class="dao.BookDao"/>
</mappers>

3) Dao的接口中通过@ResultMap注解调用

@Select("select * from book")
 @ResultMap("com.mapper.ResultMap.BookResultMap")
List<Book> selectAllBook();

第二节: @Results注解

  1. @Results注解,即可用于单表查询,也可用于多表查询

@Select("select * from book where b_id=#{id}")
@Results({
        @Result(column = "b_id",property = "id"),
        @Result(column = "b_name",property = "name"),
        @Result(column = "b_price",property = "price")
     })
Book selectBookById(int id);

第三节: 注解形式进行多表查询

  1. 注解形式进行多表查询

1) 内连接,使用@ResultMap注解

(1) 构建实体类

(2) Xml文件中写resultMap

<resultMap id="BookModelResultMap" type="pojo.BookModel">
    <id column="b_id" property="id" javaType="Integer" jdbcType="INTEGER"></id>
    <result column="b_name" property="name" javaType="String" jdbcType="VARCHAR"></result>
    <result column="b_type" property="typeId"></result>
    <result column="b_author" property="authorId"></result>
    <result column="b_publisher" property="publisherId"></result>
    <result column="b_addDate" property="addDate"></result>
    <result column="b_price" property="price"></result>
    <result column="t_name" property="typeName"></result>
    <result column="a_name" property="authorName"></result>
    <result column="p_name" property="publisherName"></result>
</resultMap>

(3) 注解进行查询

@Select("select  b_id,b_name,b_type,b_author,b_publisher,b_adddate,b_price,t_name,a_name,p_name" +
        "        from book inner join book_author on b_author=a_id inner join book_type on b_type=t_id" +
        "        inner  join book_publisher on p_id=b_publisher")
@ResultMap("com.mapper.ResultMap.BookModelResultMap")
List<BookModel> selectAll();

2) 多条SQL语句,使用@Results注解

查询类别表中制定id的类别和该类的下的所有图书(一对多)

(1) 先写子查询:BookDao中,查询指定类别id的所有图书

//查询指定类别id的所有图书
@Select("select * from book where b_type=2")
@ResultMap("com.mapper.ResultMap.BookResultMap")
List<Book> getBooksByType(Integer typeId);

(2) BookTypeDao中,查询语句(两个t_id对应,红色底色的)

//查询指定图书名称所对应的类型名称
@Select("select * from book_type where t_id=#{typeId}")—先执行
@Results({
        @Result(column = "t_id",property = "tId"),
        @Result(column = "t_name",property = "tName"),
        @Result(property = "list",column = "t_id", many = @Many(select = "dao.BookDao.getBooksByType",fetchType = FetchType.LAZY))—后执行
})
Type getTypeById(@Param("typeId") Integer typeId);

(3) 注意事项:

一对多中的@Result注解中的column是指:向子查询传递的参数,值为先查询(type表)查出的类别字段的字段名称,而不是Book的类别字段名称。

当做第二次参数的字段,要写@Result注解,即使数据表字段名称和实体类属性名称也样,也要写@Result注解,不会不能填充该列

(4) 查询结果:

 

 

3) 多条SQL语句,使用@Results注解(多对一)查询指定书名的图书信息,和他的类别信息。现查Book表,然后Book表的b_typeid作为type表查询的条件

先写关联查询booktype表的查询

//通过t_id查询当前类别的信息,此方法作为查询图书信息的二次查询
@Select("select * from booktype where t_id=#{t_id}")
BookType selectTypeById(Integer t_id);

 

在写book表的查询。Associate位于BookDao

//    多对一的查询,查询指定书名的图书和他的类名信息,拿到的参数是书名,所有book表示第一次查询
//    booktype是第二次查询,因为booktype的查询条件是book查询结果
    @Select("select * from book where b_name=#{bname}")
    @Results({
            @Result(property = "b_id",column = "b_d"),
            @Result(property = "b_name",column = "b_name"),
            @Result(property = "b_price",column = "b_price"),
            @Result(property = "b_typeid",column = "b_typeid"),
            @Result(property = "bookType",column = "b_typeid", one = @One(
                    select = "com.iss.dao.BookTypeDao.selectTypeById",fetchType = FetchType.LAZY
            ))
    })
     Book selectBookInfoAndType(String bname);

 

第四节: 注解执行动态Sql语句

  1. 注解执行动态Sql语句,一般从xml文件中复制,去掉转义字符“\n”

@Update("<script>" +
        "update book" +
        "        <set>" +
        "            <if test=\"name != null and name!=''\">" +
        "                b_name = #{name}," +
        "            </if>" +
        "            <if test=\"authorId != null and authorId!=''\">" +
        "                b_author = #{authorId}," +
        "            </if>" +
        "            <if test=\"publisherId != null and publisherId!=''\">" +
        "                b_publisher = #{publisherId}," +
        "            </if>" +
        "            <if test=\"typeId != null and typeId!=''\">" +
        "                b_type = #{publisherId}," +
        "            </if>" +
        "            <if test=\"addDate != null and addDate!=''\">" +
        "                b_adddate = #{publisherId}," +
        "            </if>" +
        "            <if test=\"desc != null and desc!=''\">" +
        "                b_desc = #{desc}," +
        "            </if>" +
        "        </set>" +
        "        where b_id = #{id}"
        +
        "</script>")
Integer updateBook(Book book);

章:MyBatis存储过程mysql

  1. mysql中创建存储过程:根据输入参数图书类型id,查询该类图书的价格平均值

 

  1. 使用MyBatis调用存储过程,通过Map传递输入和输出函数

 

1) Xml文件实现

Test类:

@Test
public void testProcedure(){
    SqlSessionFactory factory = null;
    try {
        factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml"));
        SqlSession sqlSession = factory.openSession();
        BookDao dao = sqlSession.getMapper(BookDao.class);
        Map<String,Object> map = new HashMap<String, Object>();
        map.put("typeid",1);
        map.put("avgprice",0);
        dao.selectAvgPrcieByTypeId(map);
        System.out.println(map.get("avgprice"));
        sqlSession.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

 

接口文件:

void selectAvgPrcieByTypeId(Map<String,Object> map);

 

Xml文件:

<!--    Double selectAvgPrcieByTypeId(Integer typeid);-->
    <select id="selectAvgPrcieByTypeId" statementType="CALLABLE">
        call book_avg_price(#{typeid,mode=IN,jdbcType=INTEGER},#{avgprice,mode=OUT,jdbcType=DOUBLE} )
    </select>

 

 

2) 注解方式实现

@Select("call book_avg_price(#{typeid,mode=IN,jdbcType=INTEGER},#{avgprice,mode=OUT,jdbcType=DOUBLE} )")
@Options(statementType = StatementType.CALLABLE)
void selectAvgPrcieByTypeIdWithAnnotation(Map<String,Object> map);

 

章:MyBatis缓存:对查询生效

第一节:一级缓存

  1. 级缓存

1) Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个SqlSession而言。所以在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。

2) 一级缓存的生命周期有多长

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

(2) 如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用。

(3) 如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用。

(4) SqlSession中执行了任何一个update操作(update()delete()insert()) ,都会清空PerpetualCache对象的数据,但是该对象可以继续使用

3) 怎么判断某两次查询是完全相同的查询

mybatis认为,对于两次查询,如果以下条件都完全一样,那么就认为它们是完全相同的两次查询。

(1) 传入的statementId

(2) 查询时要求的结果集中的结果范围

(3) 这次查询所产生的最终要传递给JDBC java.sql.PreparedstatementSql语句字符串(boundSql.getSql() 

(4) 传递给java.sql.Statement要设置的参数值

 

List<BookModel> list = dao.selectAll();
for(BookModel b :list){
    System.out.println(b);
}
System.out.println("==============缓存测试======");
BookModel book = dao.selectAll().get(0);
System.out.println(book);

 

结果为:

 

第二节:二级缓存

  1. 二级缓存

1) MyBatis开启二级缓存

<settings>

        <!--这个配置使全局的映射器(二级缓存)启用或禁用缓存-->

        <setting name="cacheEnabled" value="true" />

        <!-- 将积极加载改为消息加载即按需加载 -->

        <setting name="aggressiveLazyLoading" value="false"/>    </settings>

2) 在需要缓存的mapper文件的中添加:也可以不设任何属性<cache></cache>

<mapper namespace="com.iss.dao.BookDao">
<!--    以上配置创建了一个LRU缓存,并每隔60秒刷新,最大存储512个对象,而且返回的对象被认为是只读的。-->
    <cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"></cache>
    <!-- 添加,删除,更新默认的返回值类型就是整型-->
    <!--Integer addBook(Book book);-->

3) 注解方式实现二级缓存,在接口上添加@CacheNamespace(blocking = true)注解

@CacheNamespace(blocking = true)
public interface BookDao {

    @Select("select * from book")
    List<Book> selectAllBooks();

}

 

4) 测试

不开启二级缓存时,两个不同的sqlSession请求相同的方法,需要数据库查询两次

 

开启二级缓存时,验证两个不同的sqlSession对象的两次查询结果:

@Test
public void test() {
    try {
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml"));
        SqlSession sqlSession = factory.openSession();
        System.out.println("sqlsession="+sqlSession);
        BookDao dao = sqlSession.getMapper(BookDao.class);
        List<Book> list = dao.selectAllBook();
        for(Book book : list){
            System.out.println(book);
        }
        sqlSession.close();
        System.out.println("===================二级缓存=================");
        SqlSession sqlSession1 = factory.openSession();
        System.out.println("sqlsession1="+sqlSession1);
        BookDao dao1 = sqlSession1.getMapper(BookDao.class);
        list = dao1.selectAllBook();
        for(Book book : list){
            System.out.println(book);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

 

结果为:

 

第十章:MyBatis-Generator配置

  1. 准备工作

pom.xml

db.properties

  1. pom文件中添加依赖:

<dependency>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-core</artifactId>
    <version>1.3.2</version>
</dependency>

 

 

  1. pom文件中依赖外添加build标签,添加插件

<build>
<plugins>
    <plugin>
        <groupId>org.mybatis.generator</groupId>
        <artifactId>mybatis-generator-maven-plugin</artifactId>
        <version>1.3.2</version>
        <configuration>
            <verbose>true</verbose>
            <overwrite>true</overwrite>
        </configuration>
    </plugin>
</plugins>
</build>

 

 

  1. (一般不需要)在project structureAritifacts,将jarput进项目,并okapply
  2. 下载插件:idea-mybatis-generator

Setting-pulgin》搜索mybatis generator,并install

 

  1. resource下添加文件

<?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>
    <!-- 引入配置文件 -->
    <properties resource="db.properties" />

    <!-- 数据库驱动包位置 -->
    <classPathEntry
            location="E:\javaee\apache-maven-3.5.0\.m2\repository\mysql\mysql-connector-java\8.0.16\mysql-connector-java-8.0.16.jar"/>
    <!-- 一个数据库一个context -->
    <context id="book_0506">
        <commentGenerator>
            <!-- 是否去除自动生成的注释 true:是 : false:-->
            <property name="suppressAllComments" value="true" />
        </commentGenerator>

        <!-- 数据库链接URL、用户名、密码 -->
        <jdbcConnection driverClass="${mysql.driver}"
                        connectionURL="${mysql.dburl}" userId="${mysql.loginname}" password="${mysql.loginpass}" />

        <!-- 生成实体类的包名和位置  -->
        <javaModelGenerator targetPackage="com.iss.pojo"
                            targetProject="src/main/java">
            <!-- 是否针对string类型的字段在set的时候进行trim调用 -->
            <property name="trimStrings" value="true" />
        </javaModelGenerator>

        <!-- 成的SQLMapper映射文件包名和位置 -->
        <sqlMapGenerator targetPackage="com.iss.mapper1"
                         targetProject="src/main/resources" />

        <!-- 生成DAO的包名和位置 -->
        <javaClientGenerator targetPackage="com.iss.dao1"
                             targetProject="src/main/java" type="XMLMAPPER" />

        <!-- 配置表信息 -->
        <!-- schemaMySQL中描述为数据库名,Oracle数据库中描述为schema的名字[登录账号名], tableName为对应的数据库表 ,domainObjectName是要生成的实体; (更改tableName,domainObjectName,schema
            就可以了) -->
        <table tableName="user" domainObjectName="User"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false">
        </table>
        <table tableName="userinfo" domainObjectName="UserInfo"
               enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="false"
               selectByExampleQueryId="false">
        </table>

        <!-- 根据数据表情况添加对应table -->

    </context>
</generatorConfiguration>

 

  1. 添加运行

run-configration中添加maven运行项

mybatis-generator:generate -e

 

 

  1. 运行generator即可

 

posted @ 2021-05-10 19:51  YangYuJia  阅读(12)  评论(0)    收藏  举报