MyBatis学习笔记

第一章 框架概述

框架:

三层架构:页面层,业务逻辑层,数据访问层

框架:是一个半成品软件,定义好了一些基础功能,需要加入你的功能就是完善的,基础功能时可以重复使用的,可升级的。

框架特点:一般不是全能的,针对某一个领域有效

JDBC缺陷:

代码冗余(处理结果集的时候代码冗余,以及整个jdbc操作,核心语句没几句,其他都是重复的)

不能自动完成实体类和查询结果的映射(需要在处理结果集的时候手动把查询结果封装到实体类)

MyBatis框架概述

MyBatis SQL Mapper Framework For Java

SQL mapper:

sql映射,可以把数据库中的一行数据,映射为一个java对象,操作这个对象,就相当于操作表中的数据

Data Aceess Object:(DAOS)

数据库访问,对数据库进行增删改查操作

mybatis提供了哪些功能?

  1. 提供了创建Connection、Statement、ResultSet的能力,不用开发人员创建这些对象了
  2. sql语句执行能力
  3. 循环sql能力,把sql结果转化为java对象,List集合的能力
  4. 关闭资源的能力,关闭Connection、Statement、ResultSet

开发人员提供sql语句——mybatis处理sql——开发人员得到List集合或java对象(表中的数据)

总结:

mybatis是一个sql映射框架,提供操作数据库的能力,增强的JDBC,开发人员集中写sql就行了,不用关心Connection、Statement、ResultSet的创建、关闭,sql执行。

第二章 mybatis入门

入门案例:

实现步骤:

  1. 数据库新建student表

  2. 创建java项目,加入maven的mybatis坐标、mysql驱动坐标

  3. 创建实体类

  4. 创建持久层的dao接口,定义操作数据库的方法

  5. 创建一个mybatis使用的配置文件,叫做sql映射文件,用来写sql语句的,一班一个表一个sql映射文件,这个文件是xml文件,写在接口所在的目录中,文件名和接口保持一致

  6. 创建mybatis主配置文件,一般一个项目一个主配置文件,主配置文件提供了数据库的连接信息和sql映射文件的位置信息

  7. 创建使用mybatis类

主要类的介绍

1.Resource:mybatis中的一个类,负责读取主配置文件

1
InputStream in = Resources.getResourceAsStream(config);

2.SqlSessionFactoryBulider:创建SqlSessionFactory对象,

1
2
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);

3.SqlSessionFactory:重量级对象,程序创建一个对象耗时较长,使用资源比较多,在整个项目中,有一个就够用了。

1
2
3
4
5
6
7
SqlSessionFactory接口,接口实现类DefaultSqlSessionFactory
SqlSessionFactory作用: 获取SqlSession对象,
SqlSession sqlSession = factory.openSession();
openSession()方法说明:
openSession():无参数的,获取的是非自动提交事务的SqlSession对象
openSession(boolean): openSession(true)获取的是自动提交事的SqlSession对象,false 获取的是非自动提交事务的SqlSession对象

4.SqlSession:接口,定义了操作数据的方法,selectOne(),selectList(),insert(),update(),delete(),commit(),rollback()等

1
SqlSession接口的实现类DefaultSqlSession

使用要求:SqlSession对象不是线程安全的,需要在方法内部使用,在sql语句执行之前,使用openSession()获取SqlSession对象,在sql语句执行之后,使用SqlSession.close()关闭,确保它是线程安全的。线程安全就是避免共享数据被污染。

第三章

1.动态代理:

mybatis帮你创建接口实现类,在实现类中调用SqlSession的方法执行sql语句

要求:

  1. dao接口和mapper文件放在一起,同一个目录
  2. dao接口和mapper文件名称一致
  3. mapper文件中的namespace值是dao接口的全限定名称
  4. mapper文件中的<select><update><insert>等标签的id值dao接口中的方法名称
  5. dao接口中不要使用重载方法

使用SqlSession.getMapper(dao接口.calss)获取这个dao接口的对象,是一个动态代理对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* mybatis动态代理
*/
@Test
public void test3(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//mybatis动态代理 sqlSession.getMapper()
StudentDao dao = sqlSession.getMapper(StudentDao.class);
System.out.println("dao="+dao);
List<Student> list = dao.selectAllStudent();
for (Student student : list) {
System.out.println(student);
}
//关闭连接
sqlSession.close();
}

2.传入参数:

从java代码中把数据传入到mapper文件的sql语句中

  • parameType:写在mapper文件中的一个属性,表示dao接口中方法的参数的数据类型

    1
    2
    3
    4
    5
    6
    7
    8
    pubulic Student selectAll(Int id);
    <!--
    parameType:dao接口中方法参数的数据类
    值是java数据类型的全限定名或者是mybatis定义的别名
    例如:parameType="java.lang.Integer"
    parameType="int"
    注意:别名不是必需的,因为mybatis通过反射可以知道接口中方法的参数的类型
    -->
  • 一个简单类型的参数

    1
    2
    3
    <!--
    在mapper文件中,获取一个简单类型的一个参数的值,使用#{任意字符}
    -->
  • 多个参数@Param命名参数(常用)

    1
    2
    3
    接口:public List<Student> selectMultiParam(String nane,int age);
    使用:@Param("参数名") String name
    public List<Student> selectMultiParam(@Param("name")String nane,@Param("age")Int age);
  • 多个参数——使用对象(常用)

    1
    最完整方式:很少用#{对象的属性名,javaType类型名称,jdbcType数据类型} #{Student,javaType=java.lang.String,jdbcType=VARCHAR}简化方式:常用#{对象的属性名} javaType类型名称,jdbcType数据类型反射获取不用写
  • 多个参数——按位置

    1
    mybatis3.4之前,使用#{0},#{1}mybatis3.4之后,使用#{arg0},#{arg1}
  • 多个参数——使用Map

    1
    使用语法:#{map中的key}

3.#和$的区别

#:占位符,使用PrepareStatement对象执行sql语句,相当于jdbc中的 ?

$:字符串替换,使用Statement对象执行sql语句

$ 可以替换列名或者表名

4.mybatis输出结果

mybatis执行sql语句后,得到的java对象

resultType结果类型:

指sql语句执行完毕后,数据转为java对象,是任意类型的对象

​ 处理方式:

  1. mybatis执行sql语句,然后mybatis调用类的无参构造方法,创建对象
  2. mybatis把ResultSet指定列值赋给同名的属性

自定义类型的别名:

不建议使用别名,建议使用全限定名

在mybatis主配置文件中定义,

1
第一种方式:<typeAliases>	<typeAlias type="yxnu.deu.entity.Student" alias="student"/>	<typeAlias type="yxnu.deu.entity.Person" alias="person"/></typeAliases>
1
第二种方式:name是包名,这个包中的所有类,类名就是别名(类名不区分大小写)<package name="yxnu.deu.entity"/>

Map:

列名是map的可以,列值是map的value

返回map的时候最多只能返回一行记录,否则报错

resultMap:

结果映射,指定列名和java对象的属性对应关系

  • 自定义列值赋值给哪个属性
  • 当你的列名和属性名不一样时,一定是要resultMap

注:resultType和resultMap不要一起使用

当你的列名和属性名不一样时:

第一种方式:resultMap

1
<!--1.先定义resultMap    id:自定义名称    type:java类型的全限定名称2.在select标签中,使用resultMap引用1定义的--><resultMap id="studentMap" type="yxnu.edu.entity.Student">    <!--    column:列名    property:java类型的属性名    -->    <id column="id" property="id"/>    <!--    非主键列,使用result    -->    <result column="name" property="name"/>    <result column="email" property="email"/></resultMap><select id="selectAllStudent" resultMap="studentMap">    select id, name, email    from student</select>

第二种方式:起列别名

1
<select id="selectAllStudent" resultType="yxnu.edu.entity.Student">    select id as stuId, name as stuName, email as stuEmail    from student</select>

5.模糊查询

like查询

1
//like模糊查询List<Student> selectLike(String name);
1
<!--    第一种模糊查询,在java代码中指定like的内容-->    <select id="selectLike" resultType="yxnu.edu.entity.Student">        select id,name,email from student where name like #{name}    </select><!--    第二种方式,拼接出#{name} "%"-->
1
/** * 测试like查询*/@Testpublic void test7(){    SqlSession sqlSession = MybatisUtils.getSqlSession();    StudentDao dao = sqlSession.getMapper(StudentDao.class);    String name="李%";    List<Student> lists = dao.selectLike(name);    for (Student list : lists) {        System.out.println(list);    }    //关闭连接    sqlSession.close();}

第四章 动态Sql

动态sql:sql的内容是变化的,可以根据条件获取到不同sql语句,主要是指where部分,使用的是mybatis提供的标签,<if> <where> <foreach>

  • <if>是判断条件的,语法:

    1
    <if test="判断java对象的属性值">	部分sql语句</if>
    1
    //动态sql,使用java对象作为参数List<Student> selectStudentIf(Student student);
    1
    <!--动态sql<if test="使用参数java对象的属性值作为判断条件 "--><select id="selectStudentIf" resultType="yxnu.edu.entity.Student">    select id,name,email,age from student    where 1=1    <if test="name!=null and name!=''">        name=#{name}    </if>    <if test="age>0">        and age>#{age}    </if></select>
    1
    /** * 测试动态sql */    @Test    public void test8(){        SqlSession sqlSession = MybatisUtils.getSqlSession();        StudentDao dao = sqlSession.getMapper(StudentDao.class);        Student student = new Student();//        student.setName("李卡斯");        student.setAge(22);        List<Student> list = dao.selectStudentIf(student);        for (Student student1 : list) {            System.out.println(student1);        }    }

    如果是第一个<if>部门,不满足的话,在where 后面加上1=1或者id>0等恒成立条件,这样的话第二个<if>才不会sql语法报错

  • <where>是用来包含多个<if>的,当多个<if>有一个成立的,<where>会自动增加一个where关键字,并去掉 if 中多余的 and ,or等,这样的话就不用加什么1=1之类的了。

    1
    <select id="selectStudentIf" resultType="yxnu.edu.entity.Student">    select id,name,email,age from student    <where>        <if test="name!=null and name!=''">            name=#{name}        </if>        <if test="age>0">            and age>#{age}        </if>    </where></select>
  • <foreach>循环java中的数组,list集合的,主要用在sql的 in 语句中

    1
    学生id是1001,1002,1003的三个学生select * from student where id id(1001,1002,1003)
    1
    <foreach collection="" item="" open="" close="" separator="">    </foreach>

    collection:表示接口中的方法的参数的类型,如果是数组使用array,如果是list集合使用list

    item:自定义的,表示数组和集合成员的变量

    open:循环开始的字符

    close:循环结束时的字符

    separator:集合成员之间的分隔符

    1
    //foreach 用法1List<Student> selectForeach(List<Integer> list);//foreach 用法2List<Student> selectForeachTwo(List<Student> stulist);
    1
    <!--foreach使用1--><select id="selectForeach" resultType="yxnu.edu.entity.Student">    select * from student where id in    <foreach collection="list" item="myid" open="(" close=")" separator=",">        #{myid}    </foreach></select><!--foreach使用2--><select id="selectForeachTwo" resultType="yxnu.edu.entity.Student">        select * from student where id in        <foreach collection="list" item="stu" open="(" close=")" separator=","><!-- 相当于使用对象的getId()-->            #{stu.id}        </foreach></select>
    1
    /** * 测试foreach用法1 */@Testpublic void test9() {    SqlSession sqlSession = MybatisUtils.getSqlSession();    StudentDao dao = sqlSession.getMapper(StudentDao.class);    List<Integer> list = new ArrayList<>();    list.add(1001);    list.add(1002);    list.add(1003);    List<Student> list1 = dao.selectForeach(list);    for (Student student : list1) {        System.out.println(student);    }}/*** 测试foreach用法2*/    @Test    public void test10(){        SqlSession sqlSession = MybatisUtils.getSqlSession();        StudentDao dao = sqlSession.getMapper(StudentDao.class);        List<Student> stulist=new ArrayList<>();        Student student = new Student();        student.setId(1005);        stulist.add(student);        student = new Student();        student.setId(1006);        stulist.add(student);        List<Student> lists = dao.selectForeachTwo(stulist);        for (Student list : lists) {            System.out.println(list);        }    }
  • sql代码片段,就是复用一些sql语句

    步骤:先定义,再使用

    1
    1.先定义<sql id="自定义名称唯一">           sql语句,表名,字段等       </sql>           2.使用,<include refid="id值"/>       

第五章

1.数据库的属性配置文件,把数据库连接信息放到一个单独的properties文件中,和mybatis主配置文件分开

  • 在resources目录下定义一个属性配置文件,例如 jdbc.propertoes

    key:一般做多级目录,两级三级比较合适

    jdbc.mysql.driver jdbc.driver

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    mybatis主配置文件
    <!--指定properties文件的位置,从类路径开始找文件-->
    <properties resource="jdbc.properties"/>

    在resources目录下定义jdbc.properties
    jdbc.driver=com.mysql.cj.jdbc.Driver
    ...

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

2.多个mapper文件

  • 第一种就是写多个<mapper>

  • 使用包名,<package name="存放mapper文件的全限定包名"/>,这样这个包下所有的mapper文件一次都能加载给mybatis主配置文件

    使用要求:

    • mapper文件名称要和接口名称一样,区分大写的一样
    • mapper文件和dao接口在同一目录

第六章 扩展

PageHelper:用来做数据分页查询