【尚硅谷】MyBatis

一、MyBatis入门 + 接口式编程(idea实现)

1、由于是入门级demo,所以直接弄个java工程,也不用maven了
先来看工程的目录结构
【尚硅谷】MyBatis_第1张图片
这里学习下
java中build path是什么?
如果你只是将jar包复制到Java工程里面去,那么是无法使用到jar包里面的类,因为编程ide无法找到jar包。所以build path其实就是添加jar包的路径,让ide可以找到这个路径对应的jar包的文件,从而来能够使用jar包中的方法。

2、实体类

@Data
public class Employee {
   
   private Integer id;
   private String lastName;
   private String email;
   private String gender;
}

3、mybatis的全局配置文件


DOCTYPE configuration
 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-config.dtd">
<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" />
            <property name="username" value="root" />
            <property name="password" value="houchen" />
         dataSource>
      environment>
   environments>
   
   <mappers>
      <mapper resource="EmployeeMapper.xml" />
   mappers>
configuration>

4、sql映射文件 + mapper接口


DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.mybatis.mapper.EmployeeMapper">

   <select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee">
      select id,last_name lastName,email,gender from tbl_employee where id = #{id}
   select>
mapper>
public interface EmployeeMapper {

    public Employee getEmpById(int id);
}

5、测试代码

/*
    1、sqlSession代表和数据库的一次会话,用完必须关闭
    2、SqlSession是非线程安全的,每次使用都应该创建一个新的对象
    3、mapper接口没有实现类,但是mybatis会为这个接口生成一个代理对象
    4、两个重要的配置文件:
        mybatis的全局配置文件
        sql映射文件
 */
public class MybatisTest {

    public SqlSessionFactory getSqlSessionFactory() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        return sqlSessionFactory;
    }


    /*
     * 1、根据xml配置文件(mybatis的全局配置文件)创建一个SqlSessionFactory对象
     * 2、sql映射文件
     * 3、将sql映射文件注册到mybatis全局配置文件
     */
    @Test
    public void test() throws IOException {
        SqlSession openSession = getSqlSessionFactory().openSession();
        try {
            Employee employee = openSession.selectOne(
                    "com.atguigu.mybatis.dao.EmployeeMapper.getEmpById", 1);
            System.out.println(employee);
        } finally {
            openSession.close();
        }
    }

    @Test
    public void testMapper() throws IOException {
        SqlSession openSession = getSqlSessionFactory().openSession();
        EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
        Employee e = mapper.getEmpById(1);
        System.out.println(e);
    }
}

【尚硅谷】MyBatis_第2张图片

二、全局配置文件详解

1、peoperties

mybatis可以使用properties来引入外部properties配置文件的内容

  • resource:引入类路径下的资源
  • url:引入网络或者磁盘路径下的资源
    【尚硅谷】MyBatis_第3张图片

2、settings

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


<settings>
   <setting name="mapUnderscoreToCamelCase" value="true"/>
settings>

3、typeAliases 取别名


<typeAliases>
   
   

   
   <package name="com.atguigu.mybatis.bean"/>
typeAliases>

4、typeHandlers_类型处理器

5、plugins_插件简介

6、environments


<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>

7、databaseIdProvider_多数据库支持


<databaseIdProvider type="DB_VENDOR">
   <property name="MySQL" value="mysql"/> //支持mysql环境
   <property name="Oracle" value="oracle"/> //支持oracle环境
databaseIdProvider>

databaseId:告诉mybatis 这条语句是在什么环境下执行的

<select id="getEmpById" resultType="employee" databaseId="mysql">
   select id,last_name,email,gender from tbl_employee where id = #{id}
select>

8、mappers



<mappers>
   
   
   <package name="com.atguigu.mybatis.mapper"/>
mappers>

三、Mybatis- 映射文件

1、insert_获取自增主键的值


<insert id="addEmp" parameterType="com.atguigu.mybatis.bean.Employee" useGeneratedKeys="true"
   keyProperty="id">
   insert into tbl_employee(last_name,email,gender)
   values(#{lastName},#{email},#{gender})
insert>

2、insert:获取非自增主键的值selectKey


  <insert id="addEmp" databaseId="oracle">
      /*
      keyProperty: 查出的主键值封装到javaBean的哪个属性
      order = "BEFORE" 当前sql在插入sql之前运行
              "AFTER"  当前sql在插入sql之后运行
      resultType : 查出的数据的返回值类型
      */
      <selectKey keyProperty="id" order="BEFORE" resultType="Integer">
          /*编写查询主键的sql语句*/
          select employees_seq.nextval from dual;
      selectKey>
      /*插入的主键是从序列中拿到的*/
      insert into employees(id,last_name,email,gender)
values(#{lastName},#{email},#{gender})
  insert>

3、mybatis参数处理

  • 单个参数
    mybatis不会做特殊处理,#{参数名} 取出参数

  • 多个参数
    mybatis会做特殊处理,多个参数会被封装成一个map,
    key:param1…paramN
    value: 对应的按照顺序传入的参数
    #{param1} 就是从map中获取指定的值

  • 命名参数(@param(“xxx”))
    明确指定封装参数时map的key ==》接口定义时,使用@param注解
    多个参数会被封装成一个map
    key:使用@param注解指定的值
    value:参数值
    #{key} 就是从map中获取指定的值

public Employee getEmpByIdAndLastName(@Param("id") int id, @Param("lastName") String lastName);

<select id="getEmpByIdAndLastName" resultType="employee">
   select id,last_name,email,gender from tbl_employee 
   where id = #{id} and last_name =#{lastName}
</select>
  • 实体类
    如果多个参数正好是我们业务逻辑的数据原型,可以之间传入pojo;#{属性名} 取出对应的值

  • Map
    如果多个参数不是业务模型中的数据,没有对应的pojo,为了方便,我们也可以传入map
    #{key} 取出对应的值

【尚硅谷】MyBatis_第4张图片
【补充】
参数值的获取
#{} :以预编译的形式,将参数设置到sql语句中,类似于jdbc的参数占位符,防止sql注入
${} : 取出的值直接拼装在sql语句中,会有安全问题

4、select 返回list和map

如果select返回list ,resultType 取得是 list 中的泛型
如果select返回map,resultType = “map”

5、resultMap

1)自定义结果映射规则:

<resultMap id="myemp" type="com.atguigu.mybatis.bean.Employee">
    
    <id column="id" property="id">id>
    <result column="last_name" property="lastName">result>
resultMap>

<select id="getEmpById" resultMap="myemp">
    select * from tbl_employee where id = #{id}
select>

2) 级联属性封装结果:

<resultMap id="myEmpDept" type="com.atguigu.mybatis.bean.Employee">
    <id column="id" property="id">id>
    <result column="last_name" property="lastName">result>
    <result column="gender" property="gender">result>
    <result column="email" property="email">result>
    <result column="did" property="dept.id">result>
    <result column="dept_name" property="dept.deptName">result>
resultMap>

<select id="getEmpAndDept" resultMap="myEmpDept">
    select
    e.id id,
    e.last_name last_name,
    e.gender gender,
    e.email email,
    d.id did,
    d.dept_name dept_name
    from  tbl_employee e left join tbl_dept d
    on e.dept_id = d.id
    where e.dept_Id = 2
select>

【注意】Employee中有一个Department对象
【尚硅谷】MyBatis_第5张图片
【尚硅谷】MyBatis_第6张图片

3) association定义关联对象封装规则:


<resultMap id="myEmpDept1" type="com.atguigu.mybatis.bean.Employee">
    <id column="id" property="id">id>
    <result column="last_name" property="lastName">result>
    <result column="gender" property="gender">result>
    <result column="email" property="email">result>

    
    <association property="dept" javaType="com.atguigu.mybatis.bean.Department">
        <result column="did" property="id">result>
        <result column="dept_name" property="deptName">result>
    association>
resultMap>

<select id="getEmpAndDept" resultMap="myEmpDept1">
    select
    e.id id,
    e.last_name last_name,
    e.gender gender,
    e.email email,
    d.id did,
    d.dept_name dept_name
    from  tbl_employee e left join tbl_dept d
    on e.dept_id = d.id
    where e.dept_Id = #{id}
select>

4) association分步查询

先准备好department对象的mapper和 xml文件
【尚硅谷】MyBatis_第7张图片
DepartmentMapper.xml

<select id="getDeptById" resultType="com.atguigu.mybatis.bean.Department">
   select id,dept_name deptName from tbl_dept where id =#{id}
select>

EmployeeMapperPlus.xml


<resultMap id="myEmpDept2" type="com.atguigu.mybatis.bean.Employee">
    <id column="id" property="id">id>
    <result column="last_name" property="lastName">result>
    <result column="gender" property="gender">result>
    <result column="email" property="email">result>

    
    <association property="dept" select="com.atguigu.mybatis.mapper.DepartmentMapper.getDeptById" column="dept_id">
    association>
resultMap>

<select id="getEmpAndDept" resultMap="myEmpDept2">
    select
    e.id id,
    e.last_name last_name,
    e.gender gender,
    e.email email,
    e.dept_id
    from  tbl_employee e 
    where e.dept_Id = #{id}
select>

5) 分步查询&延迟加载

只有在真正用到关联对象时,才会进行第二次的分布查询
mybatis配置文件中,添加配置

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

【尚硅谷】MyBatis_第8张图片

6)collection定义关联集合封装规则

<resultMap id="myDept" type="com.atguigu.mybatis.bean.Department">
   <id column="did" property="id">id>
   <result column="dept_name" property="deptName">result>

   
   <collection property="emps" ofType="com.atguigu.mybatis.bean.Employee">
      
      <id column="eid" property="id">id>
      <result column="last_name" property="lastName">result>
      <result column="email" property="email">result>
      <result column="gender" property="gender">result>
   collection>
resultMap>

<select id="getgetDeptByIdPlus" resultMap="myDept">
   select 
   d.id did,
   d.dept_name dept_name,
   e.id eid,
   e.last_name last_name,
   e.email email,
   e.gender gender
   from tbl_dept d
   left join tbl_employee e
   on d.id =e.dept_id
   where d.id =#{id}
select>

7)collection分步查询和延迟加载


<resultMap id="myDeptStep" type="com.atguigu.mybatis.bean.Department">
   <id column="id" property="id">id>
   <result column="dept_name" property="deptName">result>
   <collection property="emps" select="com.atguigu.mybatis.mapper.EmployeeMapper.getEmpsByDeptId" column="id">

   collection>
resultMap>

<select id="getgetDeptByIdStep" resultMap="myDeptStep">
   select id,dept_name from tbl_dept where id =#{id}
select>

下图中sql打印了两次,可见确实是分步查询
【尚硅谷】MyBatis_第9张图片
【扩展】:分步查询select中方法,如果要传多列的值:
将多列的值封装成map传递
column = “{k1= column1}”

fetchType ="lazy":表示延迟加载
	-lazy :延迟加载
	-eager: 立即查询
<collection property="emps" select="com.atguigu.mybatis.mapper.EmployeeMapper.getEmpsByDeptId" column="id" fetchType="lazy">

collection>

四、Mybatis- 动态sql

1、if标签

<select id="getEmpsByConditionIf" resultType="com.atguigu.mybatis.bean.Employee">
   select * from tbl_employee
   where 1=1
   <if test="id!=null">
      and id = #{id}
   if>
   <if test="lastName!=null and lastName !=''">
      and last_name like '%${lastName}%'
   if>
   <if test="email!=null">
      and email like  '%${email}%'
   if>
   <if test="gender==0 or gender == 1">
      and gender = #{gender}
   if>
select>

2、where标签

去除动态sql中多余的and 和 or

<select id="getEmpsByConditionIf" resultType="com.atguigu.mybatis.bean.Employee">
   select * from tbl_employee
   <where>
      <if test="id!=null">
         and id = #{id}
      if>
      <if test="lastName!=null and lastName !=''">
         and last_name like '%${lastName}%'
      if>
      <if test="email!=null">
         and email like  '%${email}%'
      if>
      <if test="gender==0 or gender == 1">
         and gender = #{gender}
      if>
   where>
select>

3、trim 字符串截取

<select id="getEmpsByConditionTrim" resultType="com.atguigu.mybatis.bean.Employee">
   select * from tbl_employee
   
   <trim prefix="where" suffixOverrides="and">
      <if test="id!=null">
         id = #{id} and
      if>
      <if test="lastName!=null and lastName !=''">
         last_name like '%${lastName}%' and
      if>
      <if test="email!=null">
         email like  '%${email}%' and
      if>
      <if test="gender==0 or gender == 1">
         gender = #{gender} and
      if>
   trim>
select>

4、choose when otherwise

<select id="getEmpsByConditionChoose" resultType="com.atguigu.mybatis.bean.Employee">
   select * from tbl_employee
   <where>
      <choose>
         <when test="id!=null">
            and id = #{id}
         when>
         <when test="lastName!=null and lastName !=''">
            and last_name like '%${lastName}%'
         when>
         <otherwise>
            and gender = 1
         otherwise>
      choose>
   where>
select>

5、set

用来更新数据库中的字段

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

	 	<foreach collection="ids" item="item_id" separator=","
	 		open="where id in(" close=")">
	 		#{item_id}
	 	foreach>
	 select>

mysql foreach 批量保存



<insert id="addEmps">
	insert into tbl_employee(last_name,email,gender,dept_id)	
	values
	<foreach collection="emps" item="emp" separator=",">
		(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
	foreach>
insert>

7、内置参数_parameter&_databaseId

两个内置参数:
不只是方法传递过来的参数可以被用来判断,取值。。。
mybatis默认还有两个内置参数:

_parameter:代表整个参数
	 		单个参数:_parameter就是这个参数
	 		多个参数:参数会被封装为一个map;_parameter就是代表这个map

_databaseId:如果配置了databaseIdProvider标签。
	 		_databaseId就是代表当前数据库的别名

8、可重用sql片段

定义sql片段:

<sql id="sqlColumn">
   id,last_name,email,gender
sql>

引用sql片段:

<select id="getEmpsByConditionChoose" resultType="com.atguigu.mybatis.bean.Employee">
   select
   <include refid="sqlColumn">include>
   from tbl_employee
   <where>
      <choose>
         <when test="id!=null">
            and id = #{id}
         when>
         <when test="lastName!=null and lastName !=''">
            and last_name like '%${lastName}%'
         when>
         <otherwise>
            and gender = 1
         otherwise>
      choose>
   where>
select>

五、Mybatis- 缓存机制

mybatis包含一个非常强大的查询缓存特性,他可以非常方便的配置和定制,缓存可以极大的提高查询效率

mybatis系统中提供了两级缓存:

  • 一级缓存
  • 二级缓存

1、一级缓存体验

@Test
public void testFirstCache() throws IOException {
    SqlSession sqlSession = getSqlSessionFactory().openSession();

    EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
    Employee emp = mapper.getEmpById(1);
    System.out.println(emp);

    Employee emp1 = mapper.getEmpById(1);
    System.out.println(emp1);
    System.out.println(emp1==emp);
}

【尚硅谷】MyBatis_第10张图片
【结论】 由上面的结果可以看出
两次查询,但是只打印了一次sql语句,说明第二次查询是从缓存中直接取出的结果,而不是再一次执行查询操作

2、一级缓存失效的四种情况

一级缓存的失效情况(没有使用到当前一级缓存的情况,也就是,还需要向数据库发出查询)
1、sqlSession不同
2、sqlSession相同,但是查询条件不同
3、sqlSession相同,两次查询之间执行了增删改操作(这次操作可能对之前的数据有影响)
4、sqlSession相同,手动清除了一级缓存

3、二级缓存介绍

4、缓存有关的设置以及属性

5、缓存原理图示

6、第三方缓存整合原理

你可能感兴趣的:(#,Mybatis,mybatis)