java | (三十一)MyBatis(1)配置、映射、缓存

MyBatis是一个可以自定义SQL、存储过程和高级映射的持久层框架。MyBatis摒除了大部分的JDBC代码、手工设置参数和结果集重获。MyBatis使用简单的XML和注解来配置和映射基本数据类型、Map接口和POJO到数据库记录

SqlSessionFactory是MyBatis框架的核心引擎
SqlSessionFacrtory包含了MyBatis最基础的元数据配置并且提供访问数据库的具体SqlSession实例的维护,通常使用SqlSessionFactoryBuilder创造一个SqlSessionFactory实例

配置MyBatis

基本配置

配置xml文件
configuration.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="com/conf/dbconf.properties"/>
    <!--配置数据源信息-->
    <environments default="bizdb">
        <environment id="bizdb">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="url" value="${jdbc_url}"/>
                <property name="username" value="${jdbc_user}"/>
                <property name="driver" value="${jdbc_driver}"/>
                <property name="password" value="${jdbc_password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/domin/department-mapper.xml"/>
    </mappers>



</configuration>

当然,这里使用maven来找包

    <!-- mybatis核心包 -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.2.8</version>
    </dependency>
    <!-- jdbc的包 -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.32</version>
    </dependency>

还有很多包,就不一一列举出来了
涉及到的jdbc的conf:

jdbc_url = jdbc:oracle:thin:@127.0.0.1:1521:system
jdbc_driver = oracle.jdbc.driver.OracleDriver
jdbc_user = system
jdbc_password = ****

构建 SqlSessionFactory,获取 SqlSession

package com.util.db;

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;
import java.io.Reader;

public class MySqlSessionManager {
    
    
    /*配置myBatis基本元数据的外部xml文件路径*/
    private static final String CONFIG_FILE = "com/conf/configuration.xml";


    /*建立sqlsession*/
    public static SqlSession getSqlSession(){
    
    
        SqlSessionFactory ssf = newSqlSessionFactory();
        SqlSession sqlSession = null;
        sqlSession = ssf.openSession();
        System.out.println("sqlSession实例" + sqlSession);
        return sqlSession;
    }

    /*利用Resoure组件基于文件获取一个输入流*/
    private static SqlSessionFactory newSqlSessionFactory(){
    
    
        SqlSessionFactory ssf = null;
        Reader reader = null;
        try {
    
    
            reader = Resources.getResourceAsReader(CONFIG_FILE);
            ssf = new SqlSessionFactoryBuilder().build(reader);
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
        return ssf;
    }
}

创建类
Department.java

package com.domin;

import java.util.Date;

public class Department {
    
    
    private String id;
    private String name;
    private String code;
    private Date newDate;
    private String descs;

    public Department() {
    
    
    }

    public Department(String id, String name, String code, Date newDate, String descs) {
    
    
        this.id = id;
        this.name = name;
        this.code = code;
        this.newDate = newDate;
        this.descs = descs;
    }

    public String getId() {
    
    
        return id;
    }

    public void setId(String id) {
    
    
        this.id = id;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public String getCode() {
    
    
        return code;
    }

    public void setCode(String code) {
    
    
        this.code = code;
    }

    public Date getNewDate() {
    
    
        return newDate;
    }

    public void setNewDate(Date newDate) {
    
    
        this.newDate = newDate;
    }

    public String getDisc() {
    
    
        return descs;
    }

    public void setDisc(String disc) {
    
    
        this.descs = disc;
    }
}

创建类相关映射文件配置xml
department-mapper.xml
(这个文件命名随意,不过还是规范一些为好)

  <?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">
<mapper namespace="depns">
    <select id="queryDeplist" resultType="com.domin.Department">
        select "id","name","code","newdate","descs" from "department"
    </select>
</mapper>

同时在configuration.xml中添加mapper

    <mappers>
        <mapper resource="com/domin/department-mapper.xml"/>
    </mappers>

ok一切就绪,建立一个servlet来康康

package com.servlet;

import com.domin.Department;
import com.service.DepartmentService;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

public class testServlet extends HttpServlet {
    
    
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        List<Department> list = DepartmentService.queryDeplist();

        for(Department dep:list){
    
    
            System.out.println("名字:" + dep.getName());
            System.out.println("code:" + dep.getCode());
        }
    }
}

我在数据库中存入了一条数据
请添加图片描述
现在运行tomcat,这条数据打到了控制台上
在这里插入图片描述

采用注解的方式映射sql

注解在接口当中
IDepartmentMapper,java

package com.dao;

import com.domin.Department;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface IDepartmentMapper {
    
    
    @Select("select * from \"department\"")
    public List<Department> queryDepList();
}

在configuration.xml中,添加mapper

    <mappers>
<!--        <mapper resource="com/domin/department-mapper.xml"/>-->
        <mapper class="com.dao.IDepartmentMapper"/>
    </mappers>

在DepartmentDao.java建立方法(还有DepartmenetService调用,就不演示了)

    /*利用注解的方式实现sql映射执行*/
    public static List<Department> queryDeplist2ByMapper(){
    
    
        SqlSession sqlSession = MySqlSessionManager.getSqlSession();
        return sqlSession.getMapper(IDepartmentMapper.class).queryDepList();
    }

在sevlet中调用:

        List<Department> list2 = DepartmentService.queryDeplistByMapper();
        for(Department dep:list2){
    
    
            System.out.println("名字:" + dep.getName());
            System.out.println("code:" + dep.getCode());
        }

启动tomcat,同样将结果打出来了
在这里插入图片描述

主要API生命周期

SqlSessionFactoryBuilder实例的主要作用是为了创建一个SqlSessionFactory而生存,因此在创建一个SqlSessionFactory实例成功,这个实例就可以别丢弃,所有长时间保存此对象在内存没多大意义,推荐在某个方法体内使用

SqlSessionFactory创建后在整个应用过程中始终存储在,一个应用中一般不涉及多个数据源时,也只会有一个SqlSessionFactory实例,所以它的生命周期应该是Application。通常定义此实例为单例模式

SqlSession是操作数据库业务最主要的接口,此实例不是线程安全的不能共享此对象。它的作用域应在当前请求中或一个方法体内,也不应使用类的静态变量来引用一个Sqlession实例,甚至不要使用类的一个实例变量来引用。
绝对不能在web应用中的某个会话作用域中引用此对象,应随着用户的某个HTTP请求结束而释放此对象,在使用完SqlSession执行完数据库操作后要及时关闭SqlSession

Mapper实例必需由一个SqlSession对象所创建,而且在使用Mapper实例实现数据库操作时也必需保证创建它的SqlSession是处于打开的状态下
因此Mapperr的生命周期通常和SqlSession的生命周期相同,在一个SqlSesison关闭或销毁后,基于此SqlSesison创建的Mapper实例将不能被使用

别名typeAliases

在configuration.xml(Mybatis配置文件xml)中,由typeAliases、typeAliase配置类的别名:

    <typeAliases>
        <typeAlias type="com.domin.Department" alias="dept"/>
    </typeAliases>

在department-mapper.xml中可以使用它

<?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">
<mapper namespace="depns">
    <select id="queryDeplist" resultType="dept">
        select "id","name","code","newdate","descs" from "department"
    </select>
</mapper>

这里resultType的值为dept,使用了别名

Mybatis预定义类型别名
所用基本数据烈性别名是加前缀下划线(如int类型别名为_int)
所有基础类型的包装类行为首字母变小写(如Integer类型别名为integer)
在这里插入图片描述

    <select id="queryCountNum" resultType="integer">
        select count(id) from department
    </select>

…dao.java

    /*计算部门数*/
    public static List<Integer> queryCountNum(){
    
    
        SqlSession sqlSession = MySqlSessionManager.getSqlSession();
        return sqlSession.selectList("depns.queryCountNum");
    }

sevlet

System.out.println("共有部门数:" + DepartmentDao.queryCountNum().get(0));

结果略

environments配置

environments用来配置数据源信息,其至少要有一个数据源(environmnent子元素)配置

transactionManager子元素定义myBatis处理数据库事务的类型
myBatis处理数据库事务处理支持两种类型:
JDBC:此类型使用的提交和回滚功能,它联考使用连接的数据源来管理事务的作用域

MANAGED:此类型什么不做,从不提交、回滚和关闭连接。让其他容器或代码实现中来管理事务的全部生命周期(如spring或者JAVAEE容器)

dataSoure子元素
用来配置在某个环境下JDBC数据库属性信息。MyBatis提供三种类型的数据源
UNPOOLED:此类型每次请求的时候简单打开和关闭一个连接,不使用任何连接池技术,性能较差不推荐
POOLED:此类型缓存JDBC连接对象用于避免每次都要连接和生成连接实例而需要的验证时间(使用连接池的优点)。对于并发WEB应用,建议使用此种方式的数据源
JNDI:此类型使用匹配应用服务器上配置的数据源,通过java命名目录接口方式查找一个服务器上的数据源对象

请添加图片描述
请添加图片描述

mappers

mappers元素的总告诉Mybatis框架在初始化时如何加载SQLMap映射文件或标识了注解的接口,上面有写过,这里略了

SQL映射

select(带参数)

之前也演示过了,这里演示带有参数的
sql语句可以用:<![CDATA[]]>包围sql语句告知系统将语句汇总任何特殊字符按非语义处理.
select的属性:
在这里插入图片描述
下面以查询一个customer来说明:
customer.java

package com.domin;

public class Customer {
    
    
    private String name;
    private int age;
    private String sex;

//以下省略了构造器和get、set方法

customer-mapper.xml

<?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">
<mapper namespace="cus">
    <select id="queryCustomer" parameterType="int" resultType="com.domin.Customer">
        <![CDATA[select "name","age","sex" from "customer" where "age" > #{age}]]>
    </select>
</mapper>

注意,这个mapper的namespace要写上,不然会报错
还有,<select>中的<![CDATA[]]>在csdn这里竟然显示灰色,实际上不是注释啊!
#{}表示一个变量,里面的age没啥含义,用来占位
customDao.java,写上查询方法

package com.dao;

import com.domin.Customer;
import com.util.db.MySqlSessionManager;
import org.apache.ibatis.session.SqlSession;
import java.util.List;

public class CustomerDao {
    
    
    public static List<Customer> queryCustomer(int age){
    
    
        List<Customer> list = null;
        SqlSession sqlSession = MySqlSessionManager.getSqlSession();
        list = sqlSession.selectList("cus.queryCustomer",age);
        return list;
    }
}

这里传入了age这个参数
在servlet

        List<Customer> list3 = CustomerDao.queryCustomer(18);
        for(Customer c:list3){
    
    
            System.out.println(c.getName() + "  " + c.getAge() + "  " + c.getSex());
        }

哦,还有,在configuration.xml中加上<mapper>

        <mapper resource="com/domin/customer-mapper.xml"/>

我的数据库中的customer:
在这里插入图片描述
结果:
请添加图片描述

selectOne及返回集合

selectOne:只返回一个,而不是像selectList那样返回一个list

(接上)
customer.xml

    <select id="queryCustomerByName" parameterType="String" resultType="map">
        <![CDATA[select name,age,sex from customer where name = #{
    
    name}]]>
    </select>

dao.java

public static Map<String,Object> queryCustomerByName(String name){
    
    
    return MySqlSessionManager.getSqlSession().selectOne("cus.queryCustomerByName",name);
}

servlet

        Map<String,Object> map = CustomerDao.queryCustomerByName("liang");
        System.out.println(map.get("NAME").toString());
        System.out.println(map.get("AGE").toString());
        System.out.println(map.get("SEX").toString());

注意,这里的key要大写,否则报错
结果:
请添加图片描述

insert和update

<insert><update>通用属性
id*:SQL体育局引用唯一标识,必需属性
flushCache:执行过呢更新时是否刷新缓存数据(true、false)
useGeneratedKeys:使用利用自生成唯一标识(主键),使用域自动增长主键表
keyProperty:指定在保存对象时自动生成标识反馈到对象的哪个属性
keyColumn:指定在保存对象时自动生成标识映射道底层表的主键列名
databaseId:指定对那种数据源进行数据操作,与全局配置<databaseIdProvide>对应,用来切换数据库

insert使用演示
在department-mapper.xml中添加insert方法,传入一个map

    <insert id="addCustomer" parameterType="map" keyColumn="ID" keyProperty="id"
    flushCache="true" statementType="PREPARED">
        <![CDATA[insert into department(id,name,code,newdate,descs)
            values(#{id},#{name},#{code},#{newdate},#{descs})]]>
    </insert>

在DepartmentDao.java中:

    public static int addCustomer(Map<String,Object> map){
    
    
        SqlSession sqlSession = MySqlSessionManager.getSqlSession();
        int r = sqlSession.insert("depns.addCustomer",map);
        sqlSession.commit();
        sqlSession.close();
        return r;
    }

注意,要加上commit方法,不然找不到insert的信息
在servlet中添加map,并作为参数传入到addCustomer中

Map<String,Object> map = new HashMap<String,Object>();
        map.put("id","1");
        map.put("name","陈正");
        map.put("code","111");
        map.put("newdate",new Date());
        map.put("descs","备注");
        int r = DepartmentDao.addCustomer(map);
        System.out.println("插入:" + r);

结果为1,说明成功:
去软件看看,发现也成功了
在这里插入图片描述

update使用演示
department-mapper.xml

    <update id="updateDepartment" parameterType="map" keyColumn="ID" keyProperty="id"
            statementType="PREPARED">
        update department set name=#{name} where id = #{id}
    </update>

Dao.java

public static int updateDepartment(Map<String,Object> map){
    
    
    SqlSession sqlSession = MySqlSessionManager.getSqlSession();
    int result = sqlSession.update("depns.updateDepartment",map);
    sqlSession.commit();
    sqlSession.close();
    return result;
}

servlet

        Map<String,Object> map = new HashMap<String, Object>();
        map.put("id","33");
        map.put("name","钓鱼部");
        DepartmentDao.updateDepartment(map);

结果(与insert演示的对比,摸鱼部改成钓鱼部):
在这里插入图片描述

delete

直接演示;
department-mapper.xml

    <delete id="deleteDepartmentById" flushCache="true"
            statementType="PREPARED" parameterType="string">
        delete from department where id = #{id}
    </delete>

…Dao.java

    public static int deleteDepartmentById(String id){
    
    
        SqlSession sqlSession = MySqlSessionManager.getSqlSession();
        int result = sqlSession.delete("depns.deleteDepartmentById",id);
        sqlSession.commit();
        sqlSession.close();
        return result;
    }

servlet
删除id为1的所有行

        DepartmentDao.deleteDepartmentById("1");

结果:
在这里插入图片描述

sql重用

请添加图片描述
直接上例子:
sql标签,取代这些字符串

    <sql id="depCommon">id,name,code,newdate,descs</sql>

这个标签放入<mapper>即可
然后修改查询的<select>

    <select id="queryDeplist" resultType="dept" fetchSize="2">
            select <include refid="depCommon"/> from department
    </select>

效果相同,就不贴servlet代码了
这里的select语句不能包裹在CDATA里,不然<include>就没作用了,还会报错,解决方式未知,直接就不用CDATA了。

myBaits缓存

建立缓存:

数据缓存可以增加数据的访问操作效率,myBatis提供了设置sql的缓存策略和操sql映射中引用缓存策略;
myBatis使用cache元素在sql映射中设置缓存策略及使用ref-cache引用缓存策略。
在这里插入图片描述

MyBatis中的缓存策略
LRU-最近最少使用法(默认):移除最近较长周期内都没用被使用的对象
FIFO-先进先出:移出队列里较早的对象
SOFT-软引用:基于软引用规则,使用垃圾回收机制来移出对象
WEAK-弱引用:基于弱引用规则,使用垃圾回收机制来强制性地移出对象

cache-ref元素实现从一个mapper中引用到当前的mapper中的缓存策略并应用
在这里插入图片描述

myBatis缓存机制

在这里插入图片描述
二级缓存的使用配置

globalCatche.xml(配置全局的,自定义缓存策略)

<?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">
<mapper namespace="global-catche">
    <!--配置myBatis全局二级缓存-->
    <cache eviction="LRU" readOnly="true" flushInterval="60000" size="500"/>

</mapper>

configuration.xml中mappers中写入来源

    <mappers>
        <mapper resource="com/domin/department-mapper.xml"/>
        <mapper class="com.dao.IDepartmentMapper"/>
        <mapper resource="com/domin/customer-mapper.xml"/>
        <mapper resource="com/conf/globalCatche.xml"/>
    </mappers>

在department-mapper.xml中调用

<cache-ref namespace="global-catche"/>

二级缓存的缺陷
针对一个表的操作不再它独立的namespace下执行(单表操作)
多表操作严重受限制,导致获取缓存数据发生不正确
缓存对象类型必须是序列化的实现
数据量比较庞大时可能出现更多的未知错误

猜你喜欢

转载自blog.csdn.net/weixin_42953201/article/details/120896080