Java学习知识点小结17(Mybatis框架)


Mybatis简介

🛡1.Mybatis是一个持久化层框架(与数据库交互)
🛡2.Mybatis是一个半自动框架:Sql与Java编码分离并且sql是由开发人员通过配置文件控制
🛡3.Mybatis原理
在这里插入图片描述

🛡Mybatis使用示例(不使用maven依赖):

(1)导入mybatis的jar包,以及mysql驱动jar包下载地址

(2)创建全局配置文件 mybatis-config.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>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;characterEncoding=UTF-8&amp;userSSL=false&amp;serverTimezone=GMT%2B8"/>
                <property name="username" value="root"/>
                <property name="password" value="xjh1999"/>
            </dataSource>
        </environment>
    </environments>
<!--一定要将写好的sql映射文件注册到全局配置文件中-->
    <mappers>
        <mapper resource="EmployeeMapper.xml"/>
    </mappers>
</configuration>

(4)在数据库中创建数据表,编写对应的实体类
(这里是employee表,字段有id,last_name,eamli,gender)

(3)编写sql映射文件EmployeeMapper.xml,配置了每一个sql,以及sql封装规则

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:名称空间
id:唯一标识
resultType:返回值类型
#{id}:从传递过来的参数取出id值-->
<mapper namespace="cn.xjh.mybatis.EmployeeMapper">
    <select id="selectEmp" resultType="cn.xjh.mybatis.bean.Employee">
      select id,last_name lastname,email,gender from employee where id = #{id}
    </select>
</mapper>

(4)将sql映射文件注册到全局配置文件中 (第二步内)

写代码:
(5)根据全局配置文件创建一个SqlSessionFactory对象
(6)使用sqlSession工厂获取到sqlSession对象,使用该对象进行增删改查
(7)使用sql唯一标识告诉mybatis使用哪个sql

/**
 * @author XJH
 */
public class MyBatisTest {
    public SqlSessionFactory getSqlSessionFactory() throws IOException {
//        工具类Resources加载配置文件,并根据配置文件创建SqlSessionFactory对象
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        return new SqlSessionFactoryBuilder().build(inputStream);
    }

    @Test
    public void test01() throws IOException {
//        获取sqlSession工厂对象
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
//        获取sqlSession实例,能直接执行已经映射的sql语句。autoCommit默认为false,手动提交事务
        SqlSession openSession = sqlSessionFactory.openSession();

//        使用配置文件EmployeeMapper配置好的sql语句
        try {
            Employee employee = openSession.selectOne("cn.xjh.mybatis.EmployeeMapper.selectEmp", 1);
            System.out.println(employee.toString());
        } finally {
            openSession.close();
        }
    }
}
🛡mybatis接口式编程

首先在sql映射文件内,将namespace名称空间指定为接口的全类名,select标签id与接口的方法绑定。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:名称空间
id:唯一标识
resultType:返回值类型
#{id}:从传递过来的参数取出id值-->
<mapper namespace="cn.xjh.mybatis.dao.EmployeeMapper">
    <select id="getEmpById" resultType="cn.xjh.mybatis.bean.Employee">
      select id,last_name lastname,email,gender from employee where id = #{id}
    </select>
</mapper>

编写测试类:接口绑定配置文件后,不需要实现类也可以调用

    @Test
    public void test02() throws IOException {
//        获取sqlSession工厂对象
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
//        获取sqlSession实例,能直接执行已经映射的sql语句。
        SqlSession openSession = sqlSessionFactory.openSession();
//        获取接口的实现类对象
        try {
            EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
//        调用接口内的函数得到Emp对象
            Employee employee = mapper.getEmpById(1);
            System.out.println(employee.toString());
        }finally {
            openSession.close();
        }
    }

🛡mybatis全局配置文件

(1) <properties>标签引入外部properties配置文件,配置JDBC数据源
resource=“引入类路径下资源”" url="引入网络路径或者磁盘下路径资源

(2)⭐<settings>标签用来设置每一个设置项
name=“设置项名” value=“设置项取值”

<settings>
    <!--设置数据表字段映射类属性时满足驼峰命名原则的设置项-->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
    <!--设置控制台打印mybatis发送的sql语句-->
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

(3)<typeAliases>别名处理器,为某个java类起别名,别名默认为类名小写
<package>标签批量取别名

(4)<typeHandlers>类型转换器
(5)<plugins>插件

(6)<environments>mybatis能配置各种环境

(7)<environment>配置具体的环境,该标签有个属性id作为唯一标识(例如开发与测试环境不同,可以切换)
内部必须有两个标签:事务管理器<transactionManager>
数据源<dataSource>(POOLED使用连接池技术)

(8)<databaseIdProvider> 支持多数据库厂商的标签,在该标签内给数据库厂商配置别名
首先使用<environment>配置不同的数据库环境
然后在sql映射配置文件中配置语句时添加<databaseId>标签指定数据库(使用刚刚配置的别名)

(9)<mappers>将sql映射注册到全局映射中
resource:引用类路径下的sql映射文件
url:引用网络或磁盘路径下的sql映射文件
class:应用(注册)接口,如果有映射文件则映射文件必须与定义的接口同名,并且放在接口同一目录下;还可以使用注解配置
(重要,复杂的Dao接口写sql映射配置文件;简单的Dao接口可以直接使用注解方式)

💡知识点:源码文件夹内所有的东西都会合并在类路径下。所以为了简洁明了可以给src源代码文件夹conf配置文件夹这两个源码文件夹都分别创建同名的cn.xjh.dao包。将dao接口放在src目录下的dao包,将sql映射配置xml文件放在conf目录下的dao包。 可以实现简洁,且满足编译时映射文件与接口在同一目录下。

将文件夹变为源码文件夹的操作:
在这里插入图片描述

🛡Mybatis映射文件

(1)在sql映射配置文件mapper标签内增加
insert:映射插入语句
update:映射更新语句
delete:映射删除语句
❗在编写增删改的接口时候,mybatis允许的返回值是Integer(修改影响的行),Long,Boolean(将修改影响的行封装为修改结果)

//useGeneratedKeys="true" keyProperty="id" 代表获取自增的主键值
<insert id="addEmp" parameterType="cn.xjh.mybatis.bean.Employee"  useGeneratedKeys="true" keyProperty="id">
  insert into employee(last_name,gender,email)values (#{lastName},#{gender},#{email})
</insert>
<update id="updateEmp" parameterType="cn.xjh.mybatis.bean.Employee">
 update employee set last_name=#{lastName},gender=#{gender},email=#{email} where id=#{id}
</update>
<delete id="deleteEmpById" >
    delete from employee where id=#{id}
</delete>

测试代码:

    @Test
    public void test03() throws IOException {
//        获取sqlSession工厂对象
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
//        获取sqlSession实例,能直接执行已经映射的sql语句,openSession函数内没有参数代表手动提交事务
        SqlSession openSession = sqlSessionFactory.openSession();
//        获取接口的实现类对象
        try {
            EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
//        调用接口内的函数得到Emp对象
            mapper.addEmp(new Employee(null,"curry","goldenstatewarrior","1"));
//        手动提交事务    
            openSession.commit();
        }finally {
            openSession.close();
        }
    }

🛡参数处理

🍄单个参数,mybatis不会做特殊处理 #{参数名}:取出参数值
🍄多个参数,会做特殊处理。会将多个参数封装为一个map
key:param1;value:参入的参数值
#{param1}:取出第一个参数

🍄多参数时的传值方法(以及第五项集合参数的处理):
(1) 命名参数:多个参数时,在定义接口的时候,通过注解明确指定参数key值

 public Employee getEmpByIdAndName(@Param("id") Integer id,@Param("lastName") String lastName);

也可以直接传入map

(2) POJO
如果多个参数正好是业务逻辑模型,可以直接传入pojo

 #{属性名}:取出传入pojo属性值

(3) Map
如果多个参数不是业务模型中的数据,没有对应的pojo,也可以直接传入map

 #{key}:取出map内对应的值

(4) 如果多个参数不是业务模型中的数据,但要经常使用,推荐写一个TO 数据传输对象(例如page分页对象)

(5) 特别注意:如果参数是Collection类型或者是数组也会特殊处理,即使只有一个参数也会封装为map
key:collection[0];value是传入的第一个集合对象
如果是链表 ,key可以写成list[0];如果是数组,key可以写成array[0]

🍄#{}与${}取值的差别:
#{}是以预编译的形式,将参数设置到sql语句中,防止sql注入
${}取出的值直接拼接到sql语句中,会有安全问题
大多数情况选用#{},但在原生JDBC不支持占位符的情况(例如分库分表时候select from 表 名 , 或 者 o r d e r b y {表名},或者order by orderby{列名}),只能使用${} 直接将参数拼接在sql中。


🛡select:映射查询语句

(1)如果接口内定义函数返回值为list
接口定义:public List<Employee> getEmpById(Integer id);
在xml配置select语句时候,resultType内写的是集合中元素的类型

<select id="getEmpById" resultType="cn.xjh.mybatis.bean.Employee">
      select * from employee where id = #{id}
</select>

(2)如果接口内定义函数返回值需要返回map(key是id,value是employee对象)
接口定义:

@MapKey("id")//注解能够将存放对象的 List 转化为 key 值为对象的某一属性的 Map(对象即为value值)
     public Map<Integer,Employee> selectEmp(Integer id);

在xml配置中:(resultType内为返回的map内value的类)

<select id="selectemp" resultType="cn.xjh.mybatis.bean.Employee">
        select * from employee where id = #{id}
</select>

🛡resultMap

在这里插入图片描述
resultMap与resultType属性只能二选一
🔍(1)普通查询
首先在在映射文件内配置:

<!-- id="唯一ID方便引用",type="自定义规则的java类"-->
<resultMap id="myRM" type="cn.xjh.mybatis.bean.Employee">
    <!--id标签:指定主键列的封装规则,底层会有优化
    column:指定表中哪一列
    property:指定对应的javaBean属性-->
    <id column="id" property="id"/>

    <!--result标签:指定普通列的封装规则-->
    <result column="last_name" property="lastName"/>
    <!--其他列也会自动封装,但是自己写比较好-->
</resultMap>

在select标签内引用:

<select id="getEmpById" resultMap="myRM">
    select * from employee where id=#{id}
</select>

🔍(2)联合查询
在Employee类内有个属性为Department类的对象,存储部门信息,查询两张表,使用级联属性封装结果集到一个Emp对象内。

<resultMap id="myRM2" type="cn.xjh.mybatis.bean.Employee">
    <id column="id" property="id"/>
    <result column="last_name" property="lastName"/>
    <result column="gender" property="gender"/>
    <!--级联属性,Employee对象内的department对象的id属性-->
    <!--还可以使用association标签定义联合的bean对象属性-->
    <result column="did" property="department.id"/>
    <result column="dept_name" property="department.departmentName"/>
</resultMap>

<select id="getEmpAndDept" resultMap="myRM2">
 SELECT e.id id,e.last_name last_name,e.gender gender,d.id did,d.dept_name dept_name
 FROM employee e,department d
 WHERE e.d_id=d.id AND e.id=#{id}
</select>

🔍(3)使用association进行分步式查询
✔先按照员工id查询employee表内员工信息
✔根据查出员工信息中的d_id值去部门表查询部门信息
✔把查出的部门设置到员工中;

首先 编写DepartmentMapper接口

public interface DepartmentMapper {
    public Department getDeptById(Integer id);
}

然后是DepartmentMapper.xml配置文件

<select id="getDeptById" resultType="cn.xjh.mybatis.bean.Department">
     select id,dept_name departmentName  from department where id=#{id}
</select>

编写EmployeeMapperPlus对应的映射文件,分步查询(先查员工,再用查到的部门id查询部门,在封装好返回给员工对象,d_id是数据表的字段)

<resultMap id="myRM3" type="cn.xjh.mybatis.bean.Employee">
    <id column="id" property="id"/>
    <result column="last_name" property="lastName"/>
    <result column="gender" property="gender"/>
    <!--association定义关联对象封装规则
    select:定义 property指定的当前属性是调用select指定方法查出的结果
    column:指定将哪一列的值传给这个方法-->
    <association property="department"  select="cn.xjh.mybatis.dao.DepartmentMapper.getDeptById" column="d_id">
    </association>    
</resultMap>

<!--方法id是分步查询-->
<select id="getEmpAndDeptStep" resultMap="myRM3">
 select * from employee where id=#{id}
</select>

使用联合查询时,employee的信息和department的信息会同时查出,会造成资源浪费。
可以在全局配置文件内使用setting标签实现延迟加载,先加载主信息,等到需要使用关联信息时再去加载关联信息。

<!--延迟加载的全局开关,当开启时,所有关联对象都会延迟加载,默认为false-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--开启时,任何方法的调用都会加载该对象的所有属性,否则按需加载,默认为false-->
<setting name="aggressiveLazyLoading" value="false"/>

🔍(4)使用association定义对象内单个关联对象的封装规则。
还可以使用collection标签定义对象的关联对象集合。
🔍(5)在resultMap标签内使用鉴别器discriminator,可以简单的理解为在resultMap中的swith:case语句。
实例:

<resultMap id="myRM3" type="cn.xjh.mybatis.bean.Employee">
    <id column="id" property="id"/>
    <result column="last_name" property="lastName"/>
    <result column="gender" property="gender"/>
    <!--鉴别器实现只有性别gender为女性的时候,才封装部门属性
    column:需要判断的列名
    javaType:该列对应的java类型-->
    <discriminator javaType="String" column="gender">
        <!--resultType:指定封装的结果类型不能省略-->
        <case value="0" resultType="cn.xjh.mybatis.bean.Employee">
            <association property="department"  select="cn.xjh.mybatis.dao.DepartmentMapper.getDeptById" column="d_id"></association>
        </case>
    </discriminator>
</resultMap>

🛡动态SQL

🏎MyBatis强大特性,简化拼装SQL操作

🏎 (1)动态SQL的标签:
◾ if:判断
◾ choose(when,otherwise):选择
◾ trim(where封装查询条件,set封装修改条件):字符串裁剪
◾foreach

🏎(2)在标签内test属性里使用OGNL表达式在这里插入图片描述

🏎(3)if标签的使用实例:
接口函数定义:(输入一个对象,根据该对象有的属性进行查询)

public List<Employee> getEmpByConditionIf(Employee employee);

sql映射文件:

<select id="getEmpByConditionIf" resultType="cn.xjh.mybatis.bean.Employee">
    select * from employee where 1=1
    /*test内使用OGNL判断表达式,从传入的参数取值进行判断,遇到特殊字符需要使用转义字符*/
    <if test="id!=null">and id=#{id}</if>
    <if test="lastName!=null &amp;&amp; lastName!=&quot;&quot;">and last_name like #{lastName}</if>
    <if test="email!=null and email.trim()!=&quot;&quot;">and email=#{email}</if>
    <if test="gender==0 or gender==1">and gender=#{gender}</if>
</select>

❗在语句where后使用1=1或者使用where标签防止sql语法错误

🏎 (4)trim标签的使用实例:
prefix属性:给拼串后的整个字符串加一个前缀 (例如where,set)
prefixOverrides:前缀覆盖,去掉字符串前面多余的字符
suffix:给拼串后的整个字符串加一个后缀
suffixOverrides:后缀覆盖,去掉整个字符串后面多余的字符 (例如and或者逗号)

🏎(5)choose的使用实例:

choose标签用于分支选择,按照when标签的顺序,只会进入其中一个分支进行查询。如果都不满足表达式,则进入otherwise中。

<select id="getEmpByConditionChoose" resultType="cn.xjh.mybatis.bean.Employee">
    select * from employee
    <where>
    <choose>
        <when test="id!=null">id=#{id}</when>
        <when test="lastName!=null">last_name=#{lastName}</when>
        <when test="gender!=null">gender=#{gender}</when>
        <otherwise>1=1</otherwise>
    </choose>
    </where>
</select>

🏎(5)foreach的使用实例:
当mabatis定义的接口函数传入参数为集合时,需要构建in条件语句或者批量操作语句,使用<foreach></foreach>标签进行遍历。

批量查询:
传入id集合,查询所有的id

public List<Employee> getEmpByConditionForeach(@Param("ids") List<Integer> ids);
<select id="getEmpByConditionForeach" resultType="cn.xjh.mybatis.bean.Employee">
    select * from employee where id in
    /*collection:指定要遍历的集合,在接口参数前使用@Param注解定义
    item:将当前遍历出的元素赋值给指定的变量
    separator:每个元素之间的分隔符
    open:给遍历出所有的结果拼接一个开始字符
    close:给遍历出所有的结果拼接一个结束字符
    index:遍历list的时候是索引,遍历mao时候index表示是map的key,item是map的值*/
    <foreach collection="ids" item="id" separator="," open="(" close=")" >
      #{id}
    </foreach>
</select>

批量保存:
传入list集合,将集合内所有emp对象保存

public void addEmps(@Param("emps") List<Employee> emps);
<!--批量保存,mysql支持insert into 表名(字段名) values(),(),()-->
<insert id="addEmps">
    insert into employee(last_name,email,gender,d_id)
    values
    <foreach collection="emps" item="emp" separator=",">
        (#{emp.lastName},#{emp.email},#{emp.gender},#{emp.department.id})
    </foreach>
</insert>

🏎(6)mybatis两个内置参数
_parameter:代表接口函数传入的参数(如果是单个参数则代表这个参数,如果是多个参数则代表多个参数封装成的map)
_databaseId:如果配置了databaseId则代表当前数据库的别名

🏎(7)bind标签的使用实例:
可以将OGNL表达式的值绑定到一个变量中,方便引用

<bind name="变量名" value="OGNL表达式"/>

🏎(8)sql标签的使用实例:
抽取可以重用的sql片段
1.例如将经常需要查询或插入的列名抽取出来方便引用
2.用include标签来引用,include标签还可以自定义一些property,sql标签内部可以${}使用自定义的属性。


🛡MyBatis缓存

在这里插入图片描述

一级缓存(本地缓存):
📀(1)与数据库同一次会话期间查询到的数据会放在本地缓存中,以后如果需要相同的数据,直接从缓存中获取,不再查询。
📀(2)一级缓存失效情况:
◾sqlSession不同
◾sqlSession相同但是查询条件不同(当前缓存中还没有数据)
◾sqlSession相同,但是两次查询之间执行了增删改操作
◾openSession.clearCache(); 查询后手动清除了一级缓存

二级缓存(本地缓存):
📀一个namespace(存储作用域为Mapper)对应一个二级缓存
📀(1)工作机制:
◾当一个会话关闭,该会话一级缓存中的数据会被保存在二级缓存中,新的会话可以在二级缓存内获取已查询到的信息。
◾不同namespace查出的数据放在自己对应的缓存中(map形式)
◾只有会话提交或关闭后,该会话的一级缓存的数据才转移到二级缓存中

📀(2)使用方法:
◾在全局配置文件内开启全局二级缓存配置

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

◾在mapper.xml中使用<cache>标签配置使用二级缓存

seviction:缓存的回收策略(LRU,FIFO,SOFT,WEAK) 默认为LRU最近最少使用
flushInterval:缓存刷新间隔,设置缓存多长时间(ms)清空,默认不清空
readOnly:缓存是否只读,true直接将数据在缓存中的引用交给用户,不安全;默认false,利用序列化技术克隆一份数据,安全。
size:表示缓存存放多少个元素
type:指定自定义缓存全类名(实现Cache接口自定义缓存或者第三方缓存)

◾因为缓存需要序列化与反序列化,所以POJO对象需要实现序列化接口(implements Serializable)
在这里插入图片描述

📀(3)和缓存有关的设置:
◾在全局配置中 cacheEnabled=false:关闭缓存(二级缓存关闭,一级缓存可用)
◾在映射配置的select标签内的属性 useCashe=flase (不使用二级缓存,一级缓存可用)
◾每一个增删改标签的属性 flushCache=true (执行完成后清除所有的缓存)
◾openSession.clearCache()(清除当前Session的一级缓存,二级缓存可用)


MyBatis整合ehcache
mybatis本身缓存是简单的map实现,所以mybatis定义了cache接口,允许缓存由第三方缓存来实现,第三方缓存只要实现该接口即可。整合后就可以由mybatis在程序中调用。
使用方法:
🐾(1)导入ehcache的jar包并使用slf4j日志来记录
jar包下载地址
🐾(2)下载mybatis和ehcache的适配包
🐾(3)创建ehcache.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
 <!-- 磁盘保存路径 -->
 <diskStore path="D:\ehcache" />
 
 <defaultCache 
   maxElementsInMemory="1000"
   maxElementsOnDisk="100000"
   eternal="false" 
   overflowToDisk="true"
   timeToIdleSeconds="120"
   timeToLiveSeconds="120" 
   diskExpiryThreadIntervalSeconds="120"
   memoryStoreEvictionPolicy="LRU">
 </defaultCache>
</ehcache>
 
<!-- 
属性说明:
l diskStore:指定数据在磁盘中的存储位置。
l defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略
 
以下属性是必须的:
l maxElementsInMemory - 在内存中缓存的element的最大数目 
l maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大
l eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
l overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
 
以下属性是可选的:
l timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大
l timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
 diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.
l diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
l diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作
l memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)
 -->

🐾(3)在mapper.xml中配置自定义缓存

<mapper namespace="cn.xjh.mybatis.dao.EmployeeMapper">
    <!--配置二级缓存,EhcacheCache的全类名-->
    <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
    <select id="getEmpById" resultType="cn.xjh.mybatis.bean.Employee" useCache="true">
      select * from employee where id = #{id}
    </select>
</mapper>

🐱‍👤测试:使用两个openSession创建的mapper对象调用查找函数 getEmpById(1),第二次从缓存中获取。
在这里插入图片描述


🛡MyBatis整合Spring

☘(1)项目结构
在这里插入图片描述
添加spring框架模块:(自动配置web.xml,自动生成spring配置文件applicationContext.xml以及springmvc配置文件dispatcher-servlet.xml。
在这里插入图片描述

☘(2)首先引入所有需要的jar包
在这里插入图片描述
☘(3)引入mybatis全局配置文件以及sql映射配置文件
在这里插入图片描述
☘(4)web.xml文件编写

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
<!--spring配置-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
<!--springMVC配置-->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

☘(5)spring配置文件applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd">
    <!--Spring管理所有的业务逻辑主键-->

    <!--除了控制器不要之外,其他都扫描-->
    <context:component-scan base-package="cn.xjh.ssm" >
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!--Spring用来控制业务逻辑,数据源,事务控制,aop-->
    
    <!--引入db配置文件,里面是数据库连接的信息-->
    <context:property-placeholder location="classpath:db.properties"/>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${url}"/>
        <property name="driverClassName" value="${driverClassName}"/>
        <property name="username" value="${user}"/>
        <property name="password" value="${password}"/>
        <property name="initialSize" value="${initialSize}"/>
        <property name="maxActive" value="${maxActive}"/>
    </bean>
    <!--Spring事务管理器-->
    <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/><!--dataSource是上面的数据源id-->
    </bean>
    <!--开启基于注解的事务-->
    <tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>

    <!--整合mybatis
    目的:spring管理所有组件,包括mybatis的mapper的实现类
    1.当service层调用dao层的时候 @Autowired:自动注入mapper
    2.spring管理事务,spring声明式事务-->

    <!--一启动就创建出sqlSessionFactory对象,不再需要手动创建-->
    <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!--指定mybatis全局配置文件位置,结合使用-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <!--mapperLocations指定mapper的文件位置-->
        <property name="mapperLocations" value="classpath:EmployeeMapper.xml"/>
    </bean>

    <!--扫描所有mapper接口的实现,让mapper能自动注入-->
  <mybatis-spring:scan base-package="cn.xjh.ssm.dao"/>
</beans>

☘(6)springMVC配置文件dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"

       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
    <!--SpringMVC只控制网站跳转逻辑-->
    <!--只扫描控制器,实现注释驱动Bean定义,同时将bean自动注入容器中使用-->
    <context:component-scan base-package="cn.xjh.ssm" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!--视图解析器:配置了页面的前缀与后缀-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    <!--启用注解驱动,处理请求 @RequestMapping-->
    <mvc:annotation-driven/>
    <mvc:default-servlet-handler/>
</beans>

☘(7)整合测试:
主页内点击发起一个跳转请求
在这里插入图片描述

编写Service层EmployeeService:
service要加上注解@Service,注册到Spring容器内
@Autowired标签得到容器内已经注入的mapper对象(dao层)
调用mapper内的getEmps方法
在这里插入图片描述
Employeemapper(mapper的配置文件在参考上面sql映射配置):
在这里插入图片描述
编写控制器类EmployeeController:
控制器类加上注解@Controller
使用@Autowired标签得到容器里的service对象在这里插入图片描述
请求发送到控制类内,控制器封装查询结果并跳转到pages包下的list页面打印。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值