持久层框架mybatis---基本介绍与用法

目录

mybatis配置文件

属性(properties)

环境配置(environments)

transactionManager

数据库事务

dataSource

设置(settings)

类型别名(typeAliases)

myabtis使用

封装

参数传递

单个参数

少量多个参数

多个参数

#{}与${}区别

新增

立刻拿到id

修改

删除

结果集处理

返回简单类型

对象映射

特殊处理定义 resultMap

多表关联处理结果集

嵌套查询1

嵌套查询2

查询结果 再封装

注解

常用注解标签

单元测试

mybatis动态sql

if where

trim

choose

set

foreach

特殊符号处理

数据缓存

一级缓存

二级缓存

配置二级缓存

报错


mybatis配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--  mybatis 核心配置文件-->



<!--   导入属性文件    键值对的格式, 配置存放项目的一些参数值-->
    <properties resource="config.properties"></properties>


<!--    配置数据库相关配置,可配置多个-->
    <environments default="development">
        <environment id="development">
<!--            事务管理器的配置-->
            <transactionManager type="JDBC"/>
<!--            配置数据源  POOLED是否使用数据库连接池
            数据库连接池(缓冲池)
                现在每与数据库交互一次,创建一个数据库连接对象(Connection,SqlSession)用完就销毁
              下一次需要,重复次过程   频繁的创建销毁对象,需要开销
           池:

-->
            <dataSource type="POOLED">
                <property name="driver" value="${driverName}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${uname}"/>
                <property name="password" value="${upassword}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="mappers/AdminMapper.xml"/>
    </mappers>

</configuration>

属性(properties)

<!--   导入属性文件    键值对的格式, 配置存放项目的一些参数值-->
    <properties resource="config.properties"></properties>

在resources中创建 config.properties

driverName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/ssmdb?serverTimezone=Asia/Shanghai
uname=root
upassword=root

环境配置(environments)

transactionManager

<!--            事务管理器的配置-->            <transactionManager type="JDBC"/>
数据库事务

数据库事务:对一次数据库操作过程中,多条执行sql进行管理控制,保证一次执行中的多条sql能够作为一个整体,要么都执行成功,要么都不成功。

jdbc 自动的事务提交,事务提交后就保存到数据库。

打开数据库连接—>第一条sql---->java代码---->第二条sql---->Java代码

---->第三条sql---->关闭连接—提交事务

如果第一次sql执行后,java代码报错,后面的sql不执行,但是第一条sql对数据库进行修改,出问题。

dataSource

<!--            配置数据源  POOLED是否使用数据库连接池
            数据库连接池(缓冲池)
                现在每与数据库交互一次,创建一个数据库连接对象(Connection,SqlSession)用完就销毁
              下一次需要,重复次过程   频繁的创建销毁对象,需要开销
           池:

-->
<dataSource type="POOLED">

在这里插入图片描述

设置(settings)

<!--mybaitis 设置-->
<settings>   
    <!--日志功能-->   
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

类型别名(typeAliases)

<!--配置类型别名-->
<typeAliases>
    <!--<typeAlias type="com.ffyc.mybatispro.model.Admin" alias="Admin"></typeAlias>-->    
    <package name="com.ffyc.mybatispro.model"/> 
    <!-- 包名 --></typeAliases>

myabtis使用

读取配置文件

Reader reader = Resources.getResourceAsReader(“mybatis-config.xml”);

创建 SqlSessionFactory

SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);

创建 SqlSession

SqlSession sqlSession = sessionFactory.openSession();

获得接口代理对象

sqlSession.getMapper(接口.class);

sqlSession .close();关闭

public class TestAdmin {
    public static void main(String[] args) throws IOException, IOException {
        /*
             读取mybatis 核心的配置文件
         */
        Reader reader= Resources.getResourceAsReader("mybatis.xml");
        /*
         创建 SqlSessionFacorty
         SqlSessionFacorty 封装了所有配置信息
         SqlSessionFacorty 负责生成一个数据库连接会话对象 SqlSession对象
         SqlSessionFacorty创建开销比较大,所有在整个项目中只需要创建一次,不用销毁
         */
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);

        /* 创建 SqlSession  session会话,一次与数据库交互,类似于之前的Connection
            sessionFactory.openSession()方法 用来创建一个 SqlSession对象,
            默认无参的设置事务提交为 false 手动提交
        */
        SqlSession sqlSession=sessionFactory.openSession();

        //创建访问接口的代理对象
        AdminDao adminDao=sqlSession.getMapper(AdminDao.class);

        //使用代理对象访问对应方法,本质是调用的是接口对应的sql映射文件中那sql

        Admin admin=adminDao.findAdminById(1);
        System.out.println(admin);

        //关闭于数据库连接会话对象
        sqlSession.close();
    }
}

封装

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 MybatisUtil {
    static SqlSessionFactory sessionFactory;

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

        sessionFactory=new SqlSessionFactoryBuilder().build(reader);
    }

    public  static SqlSession getSqlSession(){
        return sessionFactory.openSession();
    }

}

封装后使用

    public static void main(String[] args) {
        SqlSession sqlSession=MybatisUtil.getSqlSession();
        AdminDao adminDao=sqlSession.getMapper(AdminDao.class);

        Admin admin=adminDao.findAdminById(1);
        System.out.println(admin);

        //关闭于数据库连接会话对象
        sqlSession.close();
    }

参数传递

单个参数

我们可直接进行传递

    <insert id="saveAdmin" parameterType="string">
        insert into admin (account)values (#{account})
    </insert>

少量多个参数

在有多个参数时,传入参数可能有多个类型,我们使用一个注解标签解决

void saveAdmin(@Param("acc") String account,@Param("pwd") String password);
    <insert id="saveAdmin" >
        insert into admin (account,password)values (#{acc},#{pwd})
    </insert>

多个参数

有大量参数,使用注解标签就比较麻烦,我们使用对象的形式传入

void saveAdmin1(Admin admin);
<insert id="saveAdmin1" parameterType="Admin">    insert into admin (account,password)values (#{account},#{password})</insert>

#{}与${}区别

#{参数名} 首先是采用预编译方式,一般用于sql传值使用,更加安全

参数名′参数名′{参数名}’ 使用字符串拼接方式传值,不安全,一般用于动态向sql传列名

<!--
    '${参数名}' 字符串拼接传值
	通过列名进行排序
     select * from goods order by  ${列名}  (列名) 
	查询特定的列
     select ${} ${}  ${} from student
 -->

新增

立刻拿到id

再新增中,我们可以立即拿到刚插入数据的id

    <!--
        useGeneratedKeys=true 取出数据库生成的主键
        keyColumn=id  告诉mybatis 那个是主键列
        keyProperty=id  指定id对应的属性,类中的属性
    -->
    <insert id="saveAdmin1" parameterType="Admin" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
        insert into admin (account,password)values (#{account},#{password})
    </insert>

修改

void upadteAdmin(Admin admin);
    <update id="upadteAdmin" parameterType="int">
        update admin set account=#{account},password=${password} where id=#{id}
    </update>

删除

void deleteAdmin(int id);
<delete id="deleteAdmin">    delete from admin where id=#{id}</delete>

结果集处理

返回简单类型

int findAdmincount();
    <select id="findAdmincount" resultType="java.lang.Integer">
        select count(*) from admin
    </select>

对象映射

如果表中的列名,与类中的属性名相同,mybatis会自动将查询结果封装

到POJO对象中。

类中必须要有无参的构造方法,(get set方法 不会直接去用)

public Admin findAdminById(int id);
<select id="findAdminById" resultType="Admin" parameterType="int">    
    select * from admin where id=#{id}
</select>

也可查询多个

List<Admin> findAdmins();
    <select id="findAdminById" resultType="Admin" parameterType="int">
        select * from admin where id=#{id}
    </select>

查询结果

[Admin{id=1, account='admin', password='111'}, Admin{id=2, account='tom', password='222'}, Admin{id=3, account='jerry', password='333'}, Admin{id=4, account='update', password='0'}]

数据库中使用下划线,Java使用驼峰命名 admin_gender adminGender

不会对对象进行赋值。

得到的值为这样

Admin{id=1, account=‘admin’, password=‘111’, adminGender=‘null’}

1.列名后加 as 修改列名

 <select id="findAdminById" resultType="Admin" parameterType="int">
        select id,account,password,admin_gender as adminGender from admin where id=#{id}
</select>

2.setting设置 mapUnderscoreToCamelCase 为true

驼峰与下划线 就可转换

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

特殊处理定义 resultMap

手动处理结果集映射

<!--    在特殊情况下,我们可以自己进行手动映射            
			type  最终返回的类型            
			id 唯一标识
-->    
<resultMap id="adminMap" type="Admin">
    <!--        将 数据库中的列,与类中的哪一个属性对应
			id标签映射主键
			result映射非主键
-->        
    <result column="gender" property="adminGender">			</result>   
</resultMap>    

<select id="findAdmins1" resultMap="adminMap">        select id,account,password,admin_gender as gender from admin
</select>

多表关联处理结果集

FULL 使用时会出现,如果查询的有两个id,学生id管理员id,就会将两个id都赋为相同的

<setting name="autoMappingBehavior" value="PARTIAL"/>

嵌套查询1

Student findStudentById(int id);
   <resultMap id="studentmap" type="Student">

        <id column="id" property="id"></id>
        <result column="num" property="num"></result>
        <result column="name" property="name"></result>
        <result column="gender" property="gender"></result>

        <association property="dorm" javaType="Dorm">
            <result column="dnum" property="num"></result>
        </association>

        <association property="admin" javaType="Admin">
            <result column="account" property="account"></result>
        </association>

    </resultMap>

    <select id="findStudentById" parameterType="int" resultMap="studentmap">
        SELECT
        s.id,
        s.num,
        s.NAME,
        s.gender,
        d.num dnum,
        a.account
        from student s LEFT JOIN dorm d on s.dormid=d.id
        LEFT JOIN admin a on s.adminid=a.id
        where s.id=#{id}
    </select>

嵌套查询2

Student findStudentById1(int id);
    <resultMap id="studentmap1" type="Student">
        <id column="id" property="id"></id>
        <result column="num" property="num"></result>
        <result column="name" property="name"></result>
        <result column="gender" property="gender"></result>
        <result column="dormid"></result>
        <result column="adminid" ></result>
        <association property="dorm" javaType="Dorm" select="findDormById" column="dormid">

        </association>

        <association property="admin" javaType="Admin" select="findAdminById" column="adminid">

        </association>
    </resultMap>

    <select id="findStudentById1" resultMap="studentmap1" parameterType="int">
        select * from student where id=#{id}
    </select>

    <select id="findDormById" parameterType="int" resultType="Dorm">
        select num from dorm where id=#{id}
    </select>

    <select id="findAdminById" parameterType="int" resultType="Admin">
        select account from admin where id=#{id}
    </select>

查询结果 再封装

在早些时候,我们在做查询时,例如查询所有宿舍和学生,学生宿舍相同情况下,宿舍号会多次打出,我们使用mybatis可以将一个宿舍的学生封装到一个集合中。

演示

宿舍类—写出如下属性的get set方法,无参构造,toString方法

 	private int id;
    private int num;
    private List<Student> students;

宿舍dao接口

List<Dorm> findDorms();

宿舍dao sql映射文件

<resultMap id="dormmap" type="Dorm">
        <id column="id" property="id"></id>
        <result column="num" property="num"></result>
<!--        封装学生集合-->
        <collection property="students" javaType="list" ofType="student">
            <result column="snum" property="num"></result>
            <result column="name" property="name"></result>
        </collection>
    </resultMap>


    <select id="findDorms" resultMap="dormmap">
        SELECT
        d.id,
        d.num,
        s.name,
        s.num snum
        FROM dorm d LEFT JOIN student s on d.id=s.dormid
    </select>

写法2

<resultMap id="dormmap1" type="Dorm">
        <id column="id" property="id"></id>
        <result column="num" property="num"></result>

        <collection property="students" javaType="list" ofType="student" select="findstudents" column="id">
            <result column="num" property="num"></result>
            <result column="name" property="name"></result>
            <result column="gender" property="gender"></result>
        </collection>
    </resultMap>

    <select id="findDorms1" resultMap="dormmap1">
        select * from dorm
    </select>

    <select id="findstudents" parameterType="int" resultType="student">
        select num,name,gender from student where dormid=#{id}
    </select>

测试

    public static void main(String[] args) {
        SqlSession sqlSession= MybatisUtil.getSqlSession();

        DormDao dormDao=sqlSession.getMapper(DormDao.class);
        List<Dorm> dormList=dormDao.findDorms();

        for (Dorm dorm:dormList){
            System.out.println("宿舍号"+dorm.getNum());
            for(Student student:dorm.getStudents()){
                System.out.println(student.getNum()+" "+ student.getName());
            }
        }
    }
结果
宿舍号518
101 张三
宿舍号618
102 李四
103 王博
104 冯采柔

注解

常用注解标签

@Insert : 插入 sql , 和 xml insert sql 语法完全一样

@Select : 查询 sql, 和 xml select sql 语法完全一样

@Update : 更新 sql, 和 xml update sql 语法完全一样

@Delete : 删除 sql, 和 xml delete sql 语法完全一样

@Param

: 入参

@Results : 设置结果集合

@Result : 结果

对于少量sql 我们可以直接使用注解标签的方式

    @Delete("delete from student where id=#{id}")
    void deleteStudent(int id);

    @Insert("insert  into student (num,name,gender)values(#{num},#{name},#{gender})")
    void saveStudent(Student student);

如果需要手动映射结果集,语句比较多,xml文件中更方便

@Select("select * from student where id=#{id}")
    @Results(id="studentmap" ,value = {
            @Result(id = true,column = "id",property = "id"),
            @Result(column = "num",property = "num")
    })
    Student findStudent(int id);

@Select(“select * from t_emp”)

@Results(id = “empMap”,value = {

@Result(column = “emp_id”,property = “empId”,id = true),

@Result(column = “emp_name”,property = “empName”),

@Result(column = “emp_tel”,property = “empTel”),

@Result(column = “emp_education”,property = “empEducation”),

@Result(column = “emp_birthday”,property = “empBirthday”)

})

List getAll();

单元测试

        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>provided</scope>
        </dependency>

在方法前加入 @Test 注解标签就可使用

mybatis动态sql

在进行有条件的查询时候,有时会出现一些问题,例如多条件查询有的条件不存在,有的存在 where前会拼接 and 等等

像这样

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG
  WHERE
  <if test="state != null">
    state = #{state}
  </if>
  <if test="title != null">
    AND title like #{title}
  </if>
  <if test="author != null and author.name != null">
    AND author_name like #{author.name}
  </if>
</select>

if where

if 标签可以对传入的条件进行判断

1.where元素会进行判断,如果where包含的标签有返回值,就插入一个where。

2.如果返回值以and或者or开头,则它会剔除掉and或者or

    <select id="findStudent" resultType="Student" parameterType="Student">
        select num,name,gender from student
            <where>
                <if test="num!=0">
                    num=#{num}
                </if>
                <if test="name!=null">
                    and name=#{name}
                </if>
                <if test="gender!=null">
                    and  gender=#{gender}
                </if>
            </where>

    </select>

trim

当 where后紧跟着 and或or的时候 取出and或or

 <select id="findStudent" resultType="Student" parameterType="Student">
        select num,name,gender from student
        <trim prefix="where" prefixOverrides="and|or">
            <if test="num!=0">
               and num=#{num}
            </if>
            <if test="name!=null">
                and name=#{name}
            </if>
            <if test="gender!=null">
                and  gender=#{gender}
            </if>
        </trim>
    </select>

choose

类似与switch,有一个满足条件就跳出,否则为默认、

otherwise 可有可无

  <select id="findStudent" resultType="Student" parameterType="Student">
        select num,name,gender from student where 1=1
        <choose>
            <when test="num!=0">
                and num=#{num}
            </when>
            <when test="name!=null">
                and name=#{name}
            </when>
            <otherwise>
                and  gender="男"
            </otherwise>
        </choose>
    </select>

set

set用于更新,用于动态包含需要更新的列,忽略其它不更新的列。

根据是否有条件成立,添加set 去除最后的 逗号

    <update id="updateStudent" parameterType="Student">
        update student
            <set>
                <if test="num!=0">num=#{num},</if>
                <if test="name!=null">name=#{name},</if>
                <if test="gender!=null">gender=#{gender}</if>
            </set>
        where id=#{id}
    </update>

update student SET name=? where id=?

name后的 逗号去除了

foreach

delete from student where id in (1,2,3)

要查询大量的或批量删除, 可将 id放入 一个数组或者集合中

void deleteStudent(Integer[] array);
    <delete id="deleteStudent">
        delete from student where id in
        <!-- array集合  item 取出的临时属性 类似增强for循环-->
        <!-- open separator分隔符 close  -->
        <foreach collection="array" item="item" open="(" separator="," close=")">
            #{item}
        </foreach>
    </delete>

还可用于查询使用 ${}列名,放到数组/集合 中

select 循环列名数组 from student

特殊符号处理

mybatis中的xml文件中,有一些特殊符号,正常书写mybatis会报错,如 < , >

需要对这些符号进行转义

特殊字符转义字符
<&lt 后面加 ; 分号
>&gt
"&quot
&apos
&&amp

还可使用 用<![CDATA[]]>标签 ,在 CDATA 内部的所有内容都会被解析器忽略。

    <select id="findStudent11" resultType="Student" parameterType="int">
        select * from student
       <where>
            <if test="value!=0">
             and
                <![CDATA[
                    id<>#{idd}
                ]]>
            </if>
        </where>
    </select>

数据缓存

缓存是什么

手机上的缓存—刚打开较慢,加载图片, ----存在手机本地

浏览器的缓存— 将一些网页信息,缓存到本地

卖票/抢购缓存— 很多人访问 – 数据缓存(运行内存) --> 数据库

**作用:**让程序更快的访问到数据,同时减少数据库的访问压力,可以将数据缓存 到内存,手机内存,客户端硬盘。存在内存中,当以后再使用时直接从 内存中读取,减小对数据库的查询次数,提高数据库的内存。

mybatis提供一级缓存和二级缓存。

一级缓存

默认开启一级缓存,一级是 SqlSession级别的,当第一次查询数据时,将查到的结果封装到SqlSession对象中,再同一个SqlSession中执行相同的第二次查询时,直接从SqlSession对象中获取。

一级缓存失效:

​ SqlSession.close关闭

​ SqlSession.clearCache 清楚缓存数据

​ 执行 新增,修改,删除操作 会修改缓存数据

 @Test
    public void find(){
        SqlSession sqlSession= MybatisUtil.getSqlSession();
        StuDao stuDao=sqlSession.getMapper(StuDao.class);
        List<Student> list=stuDao.findStudent11(3);
        List<Student> list1=stuDao.findStudent11(3);
        System.out.println(list);
        System.out.println(list);
        sqlSession.close();
    }


可看出 只执行了一次查询

在这里插入图片描述

sqlSession.clearCache();清除缓存

执行两次

在这里插入图片描述

二级缓存

Mybatis二级缓存 是SqlSessionFactory级别,将查询数据放到二级缓存中,就可实现多个sqlSession共享,关闭sqlSession 将数据存入到二级缓存中。

配置二级缓存

1.在mybatis中配置

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

2.在pojo类中实现序列化接口 java.io.Serializable

public class Student implements Serializable {
    private int id;
    private int num;
    private String name;
    private String gender;

3.再mapper映射文件中 添加 表示此mapper开启二级缓存

<mapper namespace="com.ffyc.mybatispro.dao.StuDao">
    <!--开启二级缓存--> 
    <cache></cache>

测试

@Test
    public void find1(){
        SqlSession sqlSession1= MybatisUtil.getSqlSession();
        StuDao stuDao1=sqlSession1.getMapper(StuDao.class);
        List<Student> list=stuDao1.findStudent11(3);
        sqlSession1.close();
        System.out.println(list);

        SqlSession sqlSession2= MybatisUtil.getSqlSession();
        StuDao stuDao2=sqlSession2.getMapper(StuDao.class);
        List<Student> list2=stuDao2.findStudent11(3);
        sqlSession2.close();
        System.out.println(list2);

    }

当 SqlSeesion 关闭时,会将数据存入到二级缓存

从控制台信息可以看到只执行了一次查询

在这里插入图片描述

报错

意思大概就是: 在“类java.lang.Integer”中没有名为“*”的属性的getter。

There is no getter for property named 'id' in 'class java.lang.Integer'

在使用mybatis执行下面语句是 发送错误

    <select id="findStudent11" resultType="Student" parameterType="int">
        select * from student
       <where>
            <if test="id!=0">
             and
                <![CDATA[
                    id<>#{id}
                ]]>
            </if>
        </where>
    </select>

解决 对test属性进行设置 或者在dao层添加@Param注解

<if test="id!=0"> 改为
 	<if test="_parameter!=0">或者
    <if test="value!=0">

解决原因

  1. sql在test条件中使用传递参数要放在实体对象中,不让报错找不到对象
  2. 如果不放在实体对象中传输,就在test对比中使用_parameter或者value
  3. _parameter,value代表传进来的参数,如果传进来的参数是多个,那个parameter代表get(0)第一个
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值