MyBatis框架

7 篇文章 0 订阅

一、什么是MyBatis?

       MyBatis本是apache的一个开源项目iBatis,2010年这个项目由apachesoftware foundation迁移到了google code,并且改名为MyBatis 。2013年11日转移到Github。

可以看作是jdbc的一个高级封装

二、解决的主要问题?

 减轻使用JDBC的复杂性,不用编写重复的创建Connetion ,Statement ;不用编写关闭资源代码。

直接使用java对象,表示结果数据。让开发者专注SQL的处理。其他分心的工作由MyBatis代劳。

SQL写在XML里,解除sql与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用。

提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护。

三、使用步骤

0 创建数据库和表

1 新建一个maven项目

2 修改pom.xml文件

   1)加入mybatis依赖和MySQL驱动等

<!--  依赖列表  -->
    <dependencies>
    <!--    mybatis依赖    -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.1</version>
        </dependency>

        <!--mysql驱动依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>

    </dependencies>

  2)在build标签中加入资源插件

<build>
        <!-- 资源插件:处理src/main/java目录下的xml -->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>

3 根据数据库表创建实体类

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

 5 创建mapper文件(.xml)

 Mybatis框架推荐是把sql语句和java代码分开

推荐mapper文件:定义和dao接口在同一目录下,并且名字和dao接口的名字一致,一个表对应一个mappper文件

 mapper文件内部主要介绍:

<?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="com.zhiyou.mybatis.dao.StudentMapper">

<!-- 1.约束文件
    http://mybatis.org/dtd/mybatis-3-mapper.dtd
    约束文件作用:定义和限制当前文件中可以使用的标签和属性,以及标签出现的顺序。
2.mapper是根标签
    namespace:命名空间,必须有值,不能为空。唯一值。推荐使用Dao接口的全限定名称。
    作用:参与识别sql语句的作用。
3.在mapper里面可以写<insert> , <update>,<delete>,<select>等标签。
    <insert>里面是insert语句,表示执行的insert操作
    <update>里面是 update语句
    <delete>里面是delete语句
    <select>里面是 select语句
-->
</mapper>

mapper文件中直接写sql语句即可

<select>:表示查询操作,里面是select语句

    id:要执行的sql语句的唯一标识,是一个自定义宁符串。推荐使用dao接口中的方法名称

    resultType:告诉mybatis,执行sql语句,把数据赋值给哪个类型的java对象。

                resultType的值现在使用的java对象的全限定名称

6 创建mybatis的主配置文件(xml文件),放在resources目录下

    1)定义创建连接实例的数据源对象(DataSource)

    2)引入mapper文件

<?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>
    <!--添加日志设置-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <!--起别名,只给一个实体类起别名-->
<!--    <typeAliases >-->
<!--        <typeAlias type="com.zhiyou.mybatis.entity.Student" alias="student"></typeAlias>-->
<!--    </typeAliases>-->

    <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/db_source"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>


<!--
     使用mapper的resource属性指定mapper文件的路径。这个路径是从target/classes路径开启的
使用注意:
    resource=""mapper文件的路径,使用/分割路径”一个mapper resource指定一个mapper文件

-->
    <mappers>
<!--        <mapper resource="com/zhiyou/mybatis/dao/StudentMapper.xml"/>-->
<!--        <mapper resource="com/zhiyou/mybatis/dao/MyClassMapper.xml"/>-->
<!--        <package name="com.zhiyou.mybatis.dao"/>-->
        <mapper resource="com/zhiyou/mybatis/dao/DongTaiSqlMapper.xml"></mapper>
    </mappers>
</configuration>

7 创建测试类进行测试

public class TestFindOne {
    public static void main(String[] args) throws IOException {
        //mybatis核心类
        //1 定义mybatis配置文件的位置,从类路径开始的相对路径
        String config="mybatis.xml";
        //2 读取主配置文件,使用mybatis中的Resources类
        InputStream inputStream = Resources.getResourceAsStream(config);
        //3 创建SqlSessionFactory对象,使用SqlSessionFactoryBuilder类
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        //4 获取SqlSession对象
        SqlSession sqlSession = factory.openSession();
        //5 指定要执行的sql语句的id
        //sql的id= namespace+"."+select等标签内的id属性值
        String sqlId="com.zhiyou.mybatis.dao.StudentDao"+"."+"findStudentById";
        //6 通过sqlSession的方法执行sql语句
        Student student=sqlSession.selectOne(sqlId);
        System.out.println(student);
        //7 关闭sqlSession
        sqlSession.close();
    }
}

8 日志的设置

设置日志,运行代码时可以看到sql语句和sql的执行结果

<!--添加日志设置-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

 9 事务的提交

mybatis默认执行sql语句是手动提交事务,在 insetrt update delete 操作后要手动进行事务的提交

方式1:手动提交

方式2:创建sqlsession对象时,设置自动提交

10 工具类和模板的创建

首先设置mapper的文件模板

同样主配置文件的模板也是这样创建的

创建工具类,新创建一个包util,然后再在包里创建一个类

11 mybatis 的 mapper代理方式

代理技术:由mybatis创建dao接口的实现类Proxy(DaoImpl)

使用框架创建的实现类代替你自己手动创建的实现类的功能,不用开发人员写dao接口的实现类

使用要求:mapper标签中的namespace必须设置为dao的全限定名称

                  标签内的id 必须为dao接口中的方法名称

实现方式

使用sqlSession对象的方法getmapper(dao.class)

 使用代理模式后,在主配置文件中引入mapper文件的方式可以用以下方式

直接写mapper文件所在的包的全限定名称,但是必须要求mapper文件的名字和mapper接口名字一致

四、mybatis中的一些重要的对象介绍

1 Resource:mybatis框架中的对象,一个作用就是读取配置文件的信息

2 SqlSessionFactoryBuilder:负责创建SqlSessionFatory对象

3 SqlSessionFatory:它的对象是一个重要的对象

它是一个重量级的对象,创建此对象需要更多的时间和资源。因此在项目中有一个就够了

其实它是一个接口:作用是SqlFactory的工厂,就是创建SqlSession对象

他的真正实现类是DefaultSqlSessionFactory

SqlSessionFatory的方法

OpenSession()获取一个默认的SqlSession对象,默认是需要手动提交事务的

OpenSession(boolean)boolean参数表示是否需要自动提交

 True 为自动提交,false为手动提交

4 SqlSession对象 :是通过SqlSessionFatory获取的,SqlSession本身就是一个接口

DefaultSqlSession:实现类

SqlSession作用是提供了大量的执行sql语句的方法

五、parameterType入参类型

表示参数的类型,指dao方法的形参数据类型。这个参数的数据类型是给mybatis使用,mybatis在给sql语句的参数赋值时使用。

第一个用法:Java类型的全限定名称 paramType="java.lang.Integer"

第二个用法:mybatis定义的java类型的别名 paramType="int"

paramType:mybatis可通过反射机制获取dao接口方法参数的类型,可以不写

1、dao接口方法是一个简单类型的参数时

 2、dao接口方法是多个简单类型的参数时

方式1:需要使用 @Param:命名参数,在方法的形参前面使用,定义参数名,这个名称可以用在mapper文件中

 方式2:也可以不用@Param注解,使用索引,从0开始

 3、dao接口方法的参数是一个Java对象时

一个Java对象作为方法的参数时,使用该对象的属性作为参数值使用

简单的语法:#{属性名}

Mybatis内部是这样工作的: 他会去调用此属性的getXxx()方法获取属性值

 4、dao接口方法的参数是一个map集合时

六、占位符的使用

mybatis的占位符有 #{}  和  ${} 两种

#{} 语法:#{字符}

Mybatis处理 #{ } 占位符使用的对象是PrepareStatement对象

#{}占位符处理后的sql语句为: insert into student values (?,?,?,?,?)

特点:

  • 使用的PrepareStatement对象执行sql语句效率高
  • 使用的PrepareStatement对象,能避免sql注入,sql语句执行更安全
  • #{}常作为列值来使用的,位于等号的右侧,#{}位置的值和数据类型有关的

${} 语法:${字符}

 ${}表示字符串连接,把sql语句的其他内容和${}内容使用字符串(+)连接方式连在一起

特点

1)使用Statement对象,执行sql语句,效率低

2)${}占位符的值,使用的字符串连接方式,有sql注入的风险。有代码安全的问题

3)${}数据是原样使用的,不会区分数据类型。

4)${}常用作表名或者列名,在能保证数据安全的情况下使用${}

Ps:使用该占位符时 1 方法形参处要用@Param注解 2 如果传参为字符串类型的数据时要手动加上引号

七、结果集

主要有resultTyperesultMap两个

resultType属性:在执行select时使用,作为<select>标签的属性出现的。表示结果类型,mysql执行sql语句,得到java对象的类型。它的值有两种 1)java的全限定名称 2) 起别名

1、resultType

     1) java 的全限定名称

resultType :现在使用java类型的全限定名称。表示的意思mybatis执行sq1,把ResultSet中的数据转为student类型的对象。 mybatis会做以下操作:

1.调用com.zhiyou.mybatis.entity.Student的无参数构造方法,创建对象。

Student student = new student();   //使用反射创建对象

2.同名的列赋值给同名的属性。

student.setId( rs.getInt("id"));

student.setName(rs.getString("name"));

3.得到iava对象,如果dao接口返回值是List集合,mybatis把student对象放入到List集合。

所以执行Student mystudent = dao.selectById(1001);得到数据库中 id=1001这行数据,

这行数据的列值,赋给了mystudent对象的属性。你能得到mystudent对象。就相当于是id=1001这行数据。

    2)使用别名

mybatis提供的对java类型定义简短,好记名称。

自定义别名的步骤:

1) 在mybatis主配置文件,使用typeAliase标签声明别名

2)在mapper文件中, resultType="别名"

 也可以使用   <package name="com.zhiyou.dao"/>  这样就会给该包下面所有类起别名,默认为类名开头小写

2、resultMap

常用于列名和属性不同的情况,列名和属性名相同也可以使用

id:给resultmap起一个别名

type:java实体类的全限定名称,包名+类名,如果定义别名了,写别名即可

<id> 标签:常用于设置主键列   <result>标签:常用于设置非主键列

column是数据库中表的列,property是Java实体类中的属性

 八、多表联查

1、多对一 或者 一对一

常用 association 标签

现有两张表,学生表和班级表,学生表与班级表的对应关系是多个学生对应一个班级,或者也可以说一个学生对应一个班级

实体类

 方式1:类似子查询方式 

<!--方式1:  类似子查询方式-->
    <resultMap id="studentMapper1" type="com.zhiyou.mybatis.entity.Student">
<!--   property 指的是学生表中的班级属性名  column指的是学生表中查询出来的与班级表中的关联的班级id的值  select指定哪个select标签  -->
        <association property="myClass" column="scid" select="getClass" >
            <id column="cid" property="cid"></id>
            <result column="cname" property="cname"></result>
            <result column="cbanXun" property="cbanXun"></result>
        </association>
    </resultMap>
    <!--  查询一条学生记录  -->
    <select id="getOne" resultMap="studentMapper1">
        select * from tab_stu where sid = #{id}
    </select>
    <!--  查询一条班级记录,根据学生表中查询的scid   -->
    <select id="getClass" resultType="com.zhiyou.mybatis.entity.MyClass">
        select * from tab_class where cid=#{cid}
    </select>

 方式2:联合查询方式

<!--  方式2 : 联合查询方式  -->
    <resultMap id="studentMapper2" type="com.zhiyou.mybatis.entity.Student">
        <id column="sid" property="sid"></id>
        <result column="sname" property="sname"></result>
        <result column="sex" property="sex"></result>
        <result column="sage" property="sage"></result>
        <result column="scid" property="scid"></result>
        <association property="myClass" >
            <id column="cid" property="cid"></id>
            <result column="cname" property="cname"></result>
            <result column="cbanXun" property="cbanXun"></result>
        </association>
    </resultMap>

    <select id="getOne2" resultMap="studentMapper2">
        select * from tab_stu s,tab_class c where s.sid=#{id} and s.scid=c.cid
    </select>

2、一对多

常用 collection 标签

现有两张表,班级表和学生表,一个班级可以对应多个学生,因此结果集需要映射封装

实体类

 方式1 类似子查询方式

<!--  方式1 : 类似子查询方式  -->
    <resultMap id="classMapper1" type="com.zhiyou.mybatis.entity.MyClass">
        <id column="cid" property="cid"></id>
        <!--   property 是班级里面学生集合的属性名  ofType 是集合里面存储的数据类型   -->
        <collection property="list" column="cid" ofType="com.zhiyou.mybatis.entity.Student" select="getStudent">
            <id column="sid" property="sid"></id>
            <result column="sname" property="sname"></result>
            <result column="sex" property="sex"></result>
            <result column="sage" property="sage"></result>
            <result column="scid" property="scid"></result>
        </collection>
    </resultMap>
    <select id="getOneClass" resultMap="classMapper1">
        select * from tab_class where cid=#{cid}
    </select>
    <select id="getStudent" resultType="com.zhiyou.mybatis.entity.Student">
        select * from tab_stu where scid=#{cid}
    </select>

方式2 联合查询方式

<!--  方式2 : 联合查询方式  -->
    <resultMap id="getClassmap" type="com.zhiyou.mybatis.entity.MyClass">
        <id column="cid" property="cid"></id>
        <result column="cname" property="cname"></result>
        <result column="cbanXun" property="cbanXun"></result>
        <collection property="list" ofType="com.zhiyou.mybatis.entity.Student">
            <id column="sid" property="sid"></id>
            <result column="sname" property="sname"></result>
            <result column="sex" property="sex"></result>
            <result column="sage" property="sage"></result>
            <result column="scid" property="scid"></result>
        </collection>
    </resultMap>
    <select id="getOneClass2"  resultMap="getClassmap">
        select * from tab_stu s,tab_class c where c.cid=#{cid} and s.scid=c.cid
    </select>

九、动态sql

什么是动态sql:同一个dao方法,根据不同的条件可以表示不同的sql语句,主要是where部分有变化,使用mybatis提供的标签,实现动态sql的能力,主要讲if,where,foreach,sql

1、if标签 

语法如下:

<!-- List<Student>  getAll3(Student s); -->
<!--如果参数分数合理  把参数分数作为最低分来查-->
<select id="getAll3" resultType="Student">
    select * from student where 1=1 
    <if test="score != null and score gte 0 and score lte 100">
        and score >=#{score}
    </if>
</select>

 2、where标签

使用if标签时,容易引起sql语句语法错误。使用where标签解决if产生的语法问题。

使用where时 ,里面是一个或多个if标签,当有一个if标签判断条件为true,where标签会转为WHERE关键字附加到sql语句的后面。如果if 没有一个条件为true ,忽略where和里面的if

语法格式:

<where>

     <if test=”条件”> sql语句  </if>

</where>

<!-- where标签:智能判断是否加where -->
<!-- List<Student>  getAll5(Student s); -->
<select id="getAll5" resultType="Student">
    select * from student 
    <where>
        <if test="score != null and score gte 0 and score lte 100">
            score >=#{score}
        </if>
    </where>
</select>

3、foreach标签

使用foreach可以遍历集合和数组,一般用在in语句中

<!-- List<Student>  getAll9(int[] ids); -->
<select id="getAll9" parameterType="int[]"  resultType="Student">
    <!-- select * from student where sid in(1,2,3,4) -->
    select * from student where sid in
    <foreach collection="array" item="id" separator="," open="(" index="i" close=")" >
        #{id}
    </foreach>
</select>

4、set标签

用于更新操作,可以自动判断是否去除最后一个逗号

<!-- int updateOne1(Student s); -->
<!-- 如果s中的属性有值  就更改数据库中此属性的值 -->
<update id="updateOne1" parameterType="Student">
    update student
    <set>
        <if test="sname != null">
            sname=#{sname},
        </if>
        <if test="sex eq '男'.toString()   or sex eq '女'.toString() ">
            sex=#{sex},
        </if>
        <if test="score != null and score gte 0 and score lte 100">
            score=#{score},
        </if>
        <if test="sdy != null">
            sdy=#{sdy},
        </if>
    </set>
    where sid = #{sid}
</update>

5、trim标签

<!--trim标签: prefix:整体前面加前缀  suffix:整体后面加后缀 

                  prefixOverrides:智能判断去除片段的前缀,suffixOverrides:智能判断去除片段的后缀-->

<select id="getAll8" parameterType="Student"  resultType="Student">
    select * from student
    <trim prefix="where" prefixOverrides="and | or"  suffix=" and 1=1 ">
        <if test="sex != null">
            and sex=#{sex}
        </if>
        <if test="score != null">
            or score=#{score}
        </if>
        <if test="sdy != null">
            and sdy=#{sdy}
        </if>
        <if test="sname != null">
            or sname=#{sname}
        </if>
    </trim>
</select>

6、choose标签

<!-- List<Student>  getAll7(Student s); -->
<!-- 如果性别有值 把性别作为唯一条件  如果性别没值  再判断党员  如果党员没值  再判断分数  如果分数也每值  就差stid=1作为条件 -->
<!--使用choose标签实现-->
<select id="getAll7" resultType="Student">
    select * from student 
    <where>
        <choose>
            <when test="sex != null">
                sex=#{sex}
            </when>
            <when test="sdy != null">
                sdy=#{sdy}
            </when>
            <when test="score != null">
                score  >=  #{score}
            </when>
            <otherwise>
                stid=1 
            </otherwise>
        </choose>
    </where>
</select>

7、代码片段

sql标签标示一段sql代码,可以是表名,几个字段, where条件都可以,可以在其他地方复用sql标签的内容。

使用方式:

  1. 在mapper文件中定义 sq1代码片段

<sql id="唯一字符串">部分sq1语句</sq1>

2)在其他的位置,使用include标签引用某个代码片段

8、if标签中test值的书写问题

 1)当参数是一个简单类型的参数时

 2)当方法参数是多个简单类型的参数时

 3)当方法参数是一个对象时

 十、缓存

当对数据库进行查询时  如果两次的sql语句一致 不再重复去服务数据库  直接使用上一次的查询结果
作用:提高程序效率+降低数据库服务器的压力

1、一级缓存

Mybatis对缓存提供支持,但是在没有配置的默认情况下,它只开启一级缓存,一级缓存只是相对于同一个SqlSession而言。
所以在参数和SQL完全一样的情况下,我们使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时候,如果没有声明需要刷新的情况下,SqlSession都会取出当前缓存的数据,而不会再次发送SQL到数据库。

  • 一级缓存默认是开启的

  • 一级缓存针对于同一个sqSession

  • 一级缓存使用前提:缓存不能刷新

  • 期间不能执行dml

一级缓存生命周期

a、MyBatis在开启一个数据库会话时,会 创建一个新的SqlSession对象,SqlSession对象中会有一个新的Executor对象。Executor对象中持有一个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。

b、如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用。

c、如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用。

d、SqlSession中执行了任何一个update操作(update()、delete()、insert()) ,都会清空PerpetualCache对象的数据,但是该对象可以继续使用

2、二级缓存

二级缓存是application级别的缓存/SqlSessionFactory级别的缓存
mybatis的二级缓存默认是关闭的 

二级缓存的数据会存储在硬盘上

在使用缓存的mapper映射文件中添加配置

<!--开启本mapper的namespace下的二级缓存-->
<!--
        eviction:代表的是缓存回收策略,目前MyBatis提供以下策略。
        (1) LRU,最近最少使用的,一处最长时间不用的对象
        (2) FIFO,先进先出,按对象进入缓存的顺序来移除他们
        (3) SOFT,软引用,移除基于垃圾回收器状态和软引用规则的对象
        (4) WEAK,弱引用,更积极的移除基于垃圾收集器状态和弱引用规则的对象。这里采用的是LRU,
                移除最长时间不用的对形象

        flushInterval:刷新间隔时间,单位为毫秒,这里配置的是100秒刷新,如果你不配置它,那么当
        SQL被执行的时候才会去刷新缓存。

        size:引用数目,一个正整数,代表缓存最多可以存储多少个对象,不宜设置过大。设置过大会导致内存溢出。
        这里配置的是1024个对象

        readOnly:只读,意味着缓存数据只能读取而不能修改,这样设置的好处是我们可以快速读取缓存,缺点是我们没有
        办法修改缓存,他的默认值是false,不允许我们修改
    -->
<cache eviction="LRU" flushInterval="100000" readOnly="true" size="1024"/>

在使用缓存的mapper映射文件的sql标签中添加配置:(默认是true:可以不用配置)

<!--  List<Student>  getAll1();-->
<!--可以通过设置useCache来规定这个sql是否开启缓存,ture是开启,false是关闭-->
<select id="getAll1"  resultType="Student" useCache="true">
    select * from student
</select>
<!--可以通过设置useCache来规定这个sql是否开启缓存,ture是开启,false是关闭-->
<select id="getAll2"  resultType="Student" useCache="false">
    select * from student
</select>

在核心配置文件中添加配置

<settings>
       ....
       <!--这个配置使全局的映射器(二级缓存)启用或禁用缓存-->
       <setting name="cacheEnabled" value="true" />
   </settings>

  • 14
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值