Mybatis总结

MyBatis

MyBatis本来是apache的一个开源项目iBatis,后来由apache software foundation迁移到了google code,并改名为MyBatis。2013年11月迁移到GitHub。

MyBatis是一款优秀的持久化框架,它支持定制化SQL、储存过程以及高级映射。MyBatis几乎避免了所有的JDBC代码,和手动设置参数,以及获取结果集。

搭建MyBatis

添加驱动包

		<dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.40</version>
        </dependency>

添加配置文件:src/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>
    <!--连接数据库的环境,default="环境的id"-->
    <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/chuange"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 指定maper文件的路径(maven项目从resources源文件夹下找资源)-->
    <mappers>
        <mapper resource="包名/mapper文件名"/>
    </mappers>
</configuration>

创建实体类和接口

添加Mapper文件

<mapper namespace="接口的完整路径">
		<insert id="方法名" parameterType="参数类型">
              //sql
        </insert>
		<select id="方法名" resultType="查询后的返回值类型"> 
			//sql语句---注:sql语句没有分号
        </select>
  </mapper>

修改mybatis的配置文件

修改配置文件,让该配置文件知道mapper的存在

获取SqlSession

通过该对象进行数据的操作

		//1.加载配置文件
        Reader r = Resources.getResourceAsReader("mybatis-config.xml");
        //2.创建SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //3.得到session工厂
        SqlSessionFactory factory = builder.build(r); //4.得到session
        SqlSession session = factory.openSession(); //5.调取sql语句,insert("方法的完整路径"),路径=namespace+id
        int rs = session.insert("dao.EmpDao.insertEmp", e);
        session.commit();

Mybatis实现CRUD

mapper文件中参数的读取:单个基本类型参数或者String类型参数。
mapper读取参数:#{参数名(也可以是自定义名称)}
参数类型为对象类型时,读取参数的语句:#{对象中的属性名}
insert,delete,update,select中的parameterType可以省略

多个参数的情况:将参数封装到map集合中,再将map集合传递给mapper文件,取值的时候,#{map的key值}
处理结果没有实现类的时候可以直接返回map类型

<select id="jisuan" resultType="map">

在查询的时候如果需要将查询的实体类属性自动对应的话需要保证,属性名=列名

添加:session.insert(“namespace+id”[,传递给sql的参数值]);
修改:session.update(“namespace+id”[,传递给sql的参数值]); 删除:session.delete(“namespace+id”[,传递给sql的参数值]);
单行:session.selectOne(“namespace+id”[,传递给sql的参数值]);
多行:session.selectList(“namespace+id”[,传递给sql的参数值]);
处理多个聚合函数:使用map作为方法的返回值,默认key是列名

注意:增删改的时候需要提交事务
session.commit();
session.rollback();

省略实现类

Reader r=Resources.getResourceAsReader("mybatis.xml");
SqlSession session= new SqlSessionFactoryBuilder().build(r).openSession(); 
//参数是接口的class类
StudentDao dao=session.getMapper(StudentDao.class);

ThreadLocal处理sqlSession

介绍:ThreadLocal其实并不是一个Thread,而是threadlocalvariable(线程局部变量),线程局部变量的功能其实非常简单,就是为每一个使用该变量的线程都提供一个副本,是Java中一种较为特殊的线程绑定机制,每一个线程都可以独立改变自己的副本,而不会和其他线程的副本发生冲突。

示例:

public class TestThreadLocal {
    private ThreadLocal<String> threadLocal = new ThreadLocal<>();
    private List<String> list = new ArrayList<>();

    class A extends Thread{
        @Override
        public void run() {
            //存值
            System.out.println("线程A开始存值");
            threadLocal.set("threadlocal的内容");
            list.add("arraylist的内容");
            System.out.println("A----threadLocal = " + threadLocal.get());
        }
    }

    class B extends Thread{
        @Override
        public void run() {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程B开始取值");
            System.out.println("A----threadLocal = " + threadLocal.get());
            System.out.println("list = " + list.get(0));
        }
    }

    public static void main(String[] args) {
        TestThreadLocal test = new TestThreadLocal();
        TestThreadLocal.A a = test.new A();
        TestThreadLocal.B b = test.new B();
        a.start();
        b.start();
    }
}

ThreadLocal优化SqlSession

public class SqlSessionUtil {
    private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<>();
    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            Reader reader = Resources.getResourceAsReader("mybatis.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static SqlSession getSession(){
        SqlSession session = threadLocal.get();
        if (session == null){
            session = sqlSessionFactory.openSession();
            threadLocal.set(session);
        }
        return session;
    }

    public static void closeSession(){
        SqlSession session = threadLocal.get();
        if (session != null){
            session.close();
            threadLocal.remove();
        }
    }
}

给类起别名

    <!--给实体类起别名 -->
    <typeAliases>
        <!--
        <typeAlias alias="u" type="com.yhp.bean.Users"> </typeAlias>-->
        <!--指定哪些包的类可以使用别名,默认别名:类名首字母小写(实际使用的时候,全部小写也可以做结果映射) -->
        <package name="bean"></package>
    </typeAliases>

获得新增数据的id

<insert useGeneratedKeys="true" keyProperty="userid">

Mybatis复杂查询

in查询

foreach标签中属性说明:
item 表示集合中每一个元素进行迭代的别名,等同于c标签中的var
index 指定一个名字,用于表示在迭代过程中,每次迭代的位置,可以不写
open 表示语句什么时候开始
separator 表示每次迭代之间用什么富豪作为分隔符号。
close 表示以什么结束
collection 该属性是必须制定的
list时取值是list,数组时取值是array,map时取值是map的key值
参数是list示例

	<select id="finda" resultType="student">
        select * from student where studentId in 
        <foreach collection="list" item="sid" open="(" close=")" separator=",">
            #{sid}
        </foreach>
    </select>

参数是数组

	<select id="findb" resultType="student">
        select * from student where studentId in
        <foreach collection="array" item="sid" open="(" close=")" separator=",">
            #{sid}
        </foreach>
    </select>

参数是map

	<select id="findc" resultType="student">
        select * from student where studentId in
        <foreach collection="ids" item="sid" open="(" close=")" separator=",">
            #{sid}
        </foreach>
    </select>

模糊查询

动态sql

<if test="属性名!=属性值">
	and ename like '${属性名}'
</if>

注意:test属性中读取属性值时直接写属性名
模糊查询读取属性时使el表达式,${属性名},除以上位置外,都使用#{属性名},多个条件时使用and 和 or 拼接。如果传递过来是map类型,则test属性中写的是key
#{}:相当于占位符
#{id}:其中的id可表示输入参数的名称,如果是简单类型名称可以任意。
${}:表示拼接sql语句

区间查询
between 开始值 and 结束值
列名 >= 开始值 and 列名 <=结束值

<if test="stu.endTime!=null and stu.endTime!=''"> 
  	and regdate <![CDATA[ <= ]]> #{stu.endTime}
  </if>

resultMap:
(1)处理单表关系
通过给列起别名,让别名 = 属性名,也可以实现数据的对应
resultType = “指定返回值的类型” //当列名和属性名一致的时候使用
resultMap=“key值” // 1.当列名和属性名不一致 2.做多表查询的时候

	<resultMap id="aaa" type="bean.Dept">
        <!-- 可以手动指定列名和属性名的关系 ,非主键列使用result 标签,主键
        列使用id 标签-->
        <id property="dept_no" column="deptno"></id>
        <result property="d_name" column="dname"/>
        <result property="d_loc" column="loc"/>
    </resultMap>

(2)处理多表关系
两表联查,一对多或者多对一。
注意:如果是单表查询的话,select中只要使用resultType设置返回类型即可。
如果是多表联查则需要使用resultMap标签来进行结果映射,存的一方是集合的话使用Collection子标签,存的是一方的话使用的是association子标签
格式举例
一对多:

	<resultMap type="" id="自定义名称">
        <id property="id" column="dept_id"/><!--主键列-->
        <result property="java 属性名" column="列名"/>
        <collection property="属性名" ofType="java 类型">
            <id property="属性名" column="列名"/>
            <result property="属性名" column="列名"/>
        </collection>
    </resultMap>

多对一:

	<resultMap type="" id="">
        <id property="" column=""/>
        <result property="" column=""/>
        <association property="" javaType="">
            <id property="" column=""/>
            <result property="" column=""/>
        </association>
    </resultMap>

pageHelper分页

Mybatis使用两种方式进行分页处理,sql语句只需要查询数据,不实现分页处理
方式一
Mybatis使用RowBounds对象进行分页,他是针对ResultSet结果集执行的内存分页,而非物理分页。可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来实现分页功能。
优缺点:
物理分页每次都需要访问数据库,逻辑分页只需要访问一次。
物理分页占内存比较小,逻辑分页所占内存比较高。
物理分页每次都是最新的,逻辑分页可能有滞后。

rowBounds实现分页示例

SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml")).openSession();
        List<Users> usersList = sqlSession.selectList("com.yhp.dao.UsersDao.findall",
                null, new RowBounds(0, 3));//rowBounds(开始位置,显示条数)
        for (Users users : usersList) {
            System.out.println(users.getUsername());
        }

方式二:使用分页插件
分页插件就是使用Mybatis提供的插件接口,实现自定义分页插件,在插件的拦截方法内拦截待执行的sql语句,然后重写sql。

步骤

  1. 倒入jar包
		<dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.1.6</version>
        </dependency>
  1. 在mybatis总文件中配置插件
<plugins>
	<plugin interceptor="com.github.pagehelper.PageInterceptor">
	</plugin>
</plugins>

注意:这是jar包版本为5.1之后的配置方法,5.1之前的配置方法如下

	<plugins>
        <!-- PageHelper4.1.6 -->
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <property name="dialect" value="mysql"/>
        </plugin>
    </plugins>
  1. 在执行查询前设置pageHelper。startPage(当前页,每条页数)
    示例
		//分页查询(注意事项:设置分页的值一定要在查询之前)
        // 1.在工具类中指定页码值和显示条数
        PageHelper.startPage(2, 5);
        //2.调取查询的方法,得到结果集
        Student student1 = new Student();
        //student1.setStuname("aa");
        // student1.setAddress1("昌平");
        List<Student> list = dao.findall(student1);
        //3.将list集合封装到PageInfo对象中
        PageInfo pageInfo = new PageInfo(list);
        List<Student> list2 = pageInfo.getList(); //4.得到结果
        for (Student student : list2) {
            System.out.println(student.getStuname());
        }
        System.out.println("每页显示条数:" + pageInfo.getPageSize());
        System.out.println("当前页的条数:" + pageInfo.getSize());
        System.out.println("总条数:" + pageInfo.getTotal());
        System.out.println("总页数:" + pageInfo.getPages());
        System.out.println("上一页:" + pageInfo.getPrePage());
        System.out.println("下一页:" + pageInfo.getNextPage());
        System.out.println("当前页:" + pageInfo.getPageNum());

缓存

缓存分为一级缓存和二级缓存
一级缓存:SqlSession的缓存------->自动开启
二级缓存:做到从不同的缓存中共享数据SqlSessionFactoryFactory的缓存-------->手动开启
映射配置文件中配置

	<mapper namespace="接口路径">
        <cache eviction="FIFO"
               flushInterval="60000" 
               size="512" 
               readOnly="true"/>
    </mapper>

说明:
eviction:二级缓存中,缓存对象从缓存中的移除策略,先进先出FIFO
flushInterval:刷新缓存事件间隔,单位:毫秒
size:缓存对象的个数
readOnly:是否是只读

测试代码

		//不同qlSession,要同一个sqlSessionFactory 
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml"));
        SqlSession sqlSession1 = factory.openSession();
        Student student = sqlSession1.selectOne("com.yhp.dao.StudentDao.findbystuid", 1);
        System.out.println(student.getSname());
        sqlSession1.close();
        System.out.println("===================================");
        SqlSession sqlSession2 = factory.openSession();
        student = sqlSession2.selectOne("com.yhp.dao.StudentDao.findbystuid", 1);
        System.out.println(student.getSname());
        sqlSession2.close();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值