4-6 MyBatis

简介

  • MyBatis是一个基于Java的持久层框架。
  • MyBatis采用配置文件动态管理SQL语句,并含有输入映射、输出映射机制以及数据库连接池配置。
  • ORM(Object/Relational Mapping)对象/关系映射是一种数据持久化技术,它在对象模型和关系型数据库之间建立了对应关系,并且它提供了一种机制,通过JavaBean对象操作数据库表中的数据。MyBatis是ORM解决方案。通过MyBatis可以建立SQL关系映射,便捷地实现了数据的增删改查等操作。

代码实现

  • maven依赖 pom.xml
<!-- 事务 -->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-tx</artifactId>
  <version>${spring.version}</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-jdbc</artifactId>
  <version>${spring.version}</version>
</dependency>
<!-- mybatis核心包 -->
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>3.4.6</version>
</dependency>
<!-- mybatis集成spring -->
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis-spring</artifactId>
  <version>1.3.0</version>
</dependency>
<!-- mysql驱动包 -->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>8.0.16</version>
</dependency>

<!-- 导入dbcp数据库连接池的依赖,用来在spring-mybatis.xml中配置数据库 -->
<dependency>
  <groupId>commons-dbcp</groupId>
  <artifactId>commons-dbcp</artifactId>
  <version>1.4</version>
</dependency>

<!--j2ee相关包 servlet、jsp、jstl-->
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>4.0.0</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>javax.servlet.jsp</groupId>
  <artifactId>jsp-api</artifactId>
  <version>2.2</version>
</dependency>
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>jstl</artifactId>
  <version>1.2</version>
</dependency>

xml配置实现

  • bean配置 spring.xml
<!-- 1 引入jdbc配置文件 -->
<bean id="propertyConfigurer"
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location" value="classpath:jdbc.properties" />
</bean>

<!-- 2.配置数据源-数据库连接池 -->
<bean id="dbSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${driver}" />
    <property name="url" value="${url}" />
    <property name="username" value="${username}" />
    <property name="password" value="${password}" />
    <!-- 最大空闲连接数 -->
    <property name="maxIdle" value="${maxIdle}"/>
    <!-- 初始化连接数 -->
    <property name="initialSize" value="${initialSize}"/>
    <!--最大连接等待时间,连接超时时间 单位:ms-->
    <property name="maxWait" value="${maxWait}"></property>
</bean>

<!-- 3 spring和MyBatis整合,通过spring来管理MyBatis的SqlSessionFactory会话工厂 -->
<bean id="ssf" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!-- 指定数据库连接池引用 -->
    <property name="dataSource" ref="dbSource" />
    <!-- 引入mybatis配置文件 -->
    <property name="configLocation" value="classpath:mybatis.xml"/>
    <!-- 自动扫描mapping.xml文件 -->
    <!--<property name="mapperLocations" value="classpath:mapper/*.xml"></property>-->
</bean>

<!--sqlSession模板对象,sqlSession可以实现数据库连接以及包含所有执行SQL操作的方法-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
    <constructor-arg index="0" ref="ssf" />
</bean>
  • 参数文件 jdbc.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/project1?serverTimezone=GMT%2B8&allowMultiQueries=true
username=root
password=123456

initialSize=0 
maxActive=20
maxIdle=20
minIdle=1
maxWait=60000
  • mybatis配置文件 mybatis.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>
	<!--日志打印sql语句-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <!-- mapping文件(ORM对象关系映射文件)路径配置 -->
    <mappers>
        <mapper resource="mapper/StaffMapper.xml" />
    </mappers>
</configuration>
  • mapping文件 StaffMapper.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="com.st.dao.IStaffDao"><!--namespace属性关联dao层-->

    <!--orm 对象和数据表之间的映射关系-->
    <resultMap id="baseMap" type="com.st.model.Staff">
        <!--
        column 指定数据表字段
        property 指定类属性
        jdbcType 指定数据类型 int-INTEGER string-VARCHAR
        -->
        <result column="staff_id"   property="staffId"   jdbcType="INTEGER"/>
        <result column="staff_name" property="staffName" jdbcType="VARCHAR"/>
        <result column="phone"      property="phone"     jdbcType="VARCHAR"/>
    </resultMap>

    <!--
    parameterType 参数类型
    resultMap 结果集映射 对应的是resultMap.id
    -->
	<select id="queryOne" parameterType="java.lang.Integer" resultMap="baseMap">
        SELECT * FROM staff WHERE staff_id = #{staffId}
    </select>

    <select id="queryAll" parameterType="com.st.model.Staff" resultMap="baseMap">
        <!-- #{} 会自动在变量前后拼一个英文单引号-->
        SELECT * FROM staff
        <where> <!-- where标签会把标签中的第一条if语句中的and去掉-->
            <if test="staffId  != null ">AND staff_id = #{staffId} </if>
            <if test="staffName != null ">AND staff_name = #{staffName} </if>
            <if test="phone     != null ">AND phone = #{phone} </if>
        </where>
    </select>

    <!--插入语句没有返回值,但是会自动返回执行sql语句影响的行数,数据类型是integer-->
    <insert id="add" parameterType="com.st.model.Staff">
        insert into staff
        <!--
        prefix 前缀
        suffix 后缀
        suffixOverrides 去除拼接语句中的最后一个逗号
        -->
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="staffName != null">staff_name,</if>
            <if test="phone     != null">phone,</if>
        </trim>
        <trim prefix="VALUES(" suffix=")" suffixOverrides=",">
            <if test="staffName != null">#{staffName},</if>
            <if test="phone != null">#{phone},</if>
        </trim>
    </insert>

    <!--批量插入-->
    <insert id="addBatch" parameterType="java.util.List">
        <!--
       使用批量插入需要在jdbc:url中添加allowMultiQueries=true
       作用:
       1.可以在sql语句后携带分号,实现多语句执行。
       2.可以执行批处理,同时发出多个SQL语句。

       collection 被遍历的结果集
       item 本次遍历获取的元素别名
       index 当前迭代的次数
       separator 在每一句sql语句后拼接分号(;)
       -->
        <foreach collection="list" item="staff" index="index" separator=";">
            INSERT INTO staff
            <trim prefix="(" suffix=")" suffixOverrides=",">
                <if test="staff.staffId != null">staff_id,</if>
                <if test="staff.staffName != null">staff_name,</if>
                <if test="staff.phone     != null">phone,</if>
            </trim>
            <trim prefix="VALUES(" suffix=")" suffixOverrides=",">
                <if test="staff.staffId != null">#{staff.staffId, jdbcType=INTEGER},</if>
                <if test="staff.staffName != null">#{staff.staffName, jdbcType=VARCHAR},</if>
                <if test="staff.phone     != null">#{staff.phone, jdbcType=VARCHAR},</if>
            </trim>
        </foreach>
    </insert>

    <!--
    插入同时返回主键
    useGeneratedKeys 设置是否使用JDBC的getGeneratedKeys方法获取主键并赋值到keyProperty设置属性中
    keyProperty 实体类主键属性
    -->
    <insert id="addReturnPK" parameterType="com.st.model.Staff" useGeneratedKeys="true" keyProperty="staffId">
        <!--        insert into staff(staff_name, phone) values(#{staffName},#{phone});-->
        insert into staff
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="staffName != null">staff_name,</if>
            <if test="phone     != null">phone,</if>
        </trim>
        <trim prefix="VALUES(" suffix=")" suffixOverrides=",">
            <if test="staffName != null">#{staffName},</if>
            <if test="phone != null">#{phone},</if>
        </trim>
    </insert>

    <!--更新-->
    <update id="update" parameterType="com.st.model.Staff">
        update staff
        <set>
            <if test="staffName != null">staff_name = #{staffName},</if>
            <if test="phone != null">phone = #{phone},</if>
        </set>
        <where>
            <if test="staffId != null">and staff_id = #{staffId}</if>
        </where>
    </update>
</mapper>
  • Dao中调用sqlSession
package com.st.dao.impl;

import com.st.dao.IStaffDao;
import com.st.model.Staff;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.List;

@Repository
public class StaffDao implements IStaffDao {
    @Autowired
    private SqlSession sqlSession;

    private String namespace = "com.st.dao.IStaffDao.";

    @Override
    public Staff queryOne(Integer id) {
        //指定mapper的namespace和传入参数
        Staff s = sqlSession.selectOne(namespace + "queryOne", id);
        return s;
    }

    @Override
    public List<Staff> queryAll(Staff s) {
        return sqlSession.selectList(namespace + "queryAll", s);
    }

    @Override
    public int add(Staff s) {
        return sqlSession.insert(namespace + "add", s);
    }

    @Override
    public int addBatch(List<Staff> list) {
        return sqlSession.insert(namespace + "addBatch", list);
    }

    @Override
    public int addReturnPK(Staff s) {
        return sqlSession.insert(namespace + "addReturnPK", s);
    }

    @Override
    public int update(Staff s) {
        return sqlSession.update(namespace + "update", s);
    }
}

注解实现

待续

${} 与 #{} 的区别

  1. #{}与${}都是从参数列表中取值;
  2. #{}是编译好SQL语句再取值;${}是取值以后再去编译SQL语句;
  3. #{}是经过预编译的,是安全的。#{}引用参数的时候,Mybatis会把这个参数认为是一个字符串,并自动加上单引号’’;
  4. ${}是未经过预编译的,仅仅是取变量的值,是非安全的,存在SQL注入的风险;
  • 举例:
select * from staff where id=#{id}

传入id = " or 1=1"时,sql为

select * from staff where id='1 or 1=1'

但对于 ${}

select * from staff where id=${id}

传入id = " or 1=1"时,sql为

select * from staff where id=1 or 1=1

此时 ${} 显然是不安全的

mybatis一级缓存与二级缓存

  • 设置缓存后,在参数和SQL完全一样的情况下, 多次调用mapper方法,只会执行一次SQL,第一次执行sql查询到的结果集会被保存在缓存中,后面重复调用mapper方法返回的是缓存中的结果集。
  • 缓存的意义:提高对数据库查询的效率,提高应用程序的性能

一级缓存

1 一级缓存是默认开启的;
2 一级缓存只是相对于同一个SqlSession而言

二级缓存

1 二级缓存默认不开启的;
2 二级缓存是Application级别的缓存;
3 二级缓存要求返回的POJO(简单java类)必须是可序列化的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值