Mybatis

JDBC
sql夹在Java代码中,耦合度高,维护不易且实际开发需求中sql有变化,频繁修改情况多
Hibernate和JPA
基于全映射的全自动框架,大量字段的POJO进行部分映射时比较困难,导致数据库性能下降

Mybatis
sql和Java代码分开,功能边界清晰,一个专注业务,一个专注数据

 

package com.tang.bean;

public class User {
    private int id;
    private String username;
    private String password;
    private int permission;

    public User() {
    }

    public User(int id, String username, String password, int permission) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.permission = permission;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getPermission() {
        return permission;
    }

    public void setPermission(int permission) {
        this.permission = permission;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", permission=" + permission +
                '}';
    }
}

  

package com.tang.dao;

import com.tang.bean.User;

public interface UserDao {
    public User getUserById(int id);
    public int updateUser();
    public int deleteUser();
    public int insertUser();
}

  

dataSource.properties

data.driver=com.mysql.cj.jdbc.Driver
data.url=jdbc:mysql://localhost:3306/menumanage?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
data.username=root
data.password=admin

  

mybatis-config

<?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>

    <properties resource="dataSource.properties"></properties>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!--配置连接池-->
            <dataSource type="POOLED">
                <!-- ${} 取出配置文件中的值-->
                <property name="driver" value="${data.driver}"/>
                <property name="url" value="${data.url}"/>
                <property name="username" value="${data.username}"/>
                <property name="password" value="${data.password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--引入编写的每一个接口的实现文件-->
    <mappers>
        <mapper resource="UserDao.xml"/>

    </mappers>

</configuration>

  

UserDao.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">
<!--
    namespace:名称空间,写接口的全类名,相当于告诉Mybatis这个配置文件是实现哪个接口的
-->
<mapper namespace="com.tang.dao.UserDao">

    <!--select:用来定义一个查询操作
        id:方法名,相当于这个配置是对某个方法的实现
        resultType:指定方法运行后的返回值类型(查询操作必须指定)
    -->
    <select id="getUserById" resultType="com.tang.bean.User">
        select * from usertb where id = #{id}
    </select>

    <update id="updateUser">
        update usertb set username = #{username}, password = #{password}, permission = #{permission} where id = #{id}
    </update>

    <delete id="deleteUser">
        delete from usertb where id = #{id}
    </delete>

    <insert id="insertUser">
        insert into usertb(username, password, permission) value(#{username},#{password},#{permission})
    </insert>
</mapper>

  

查询语句传参问题

现象:

  • 单个参数:
    • #{任意字符串}
  • 多个参数:
    • 例如 public User getUserByIdAndName(Integer id, String username);
    • #{参数名} 无效
    • 原因:如果传入了多个参数,mybatis会自动将这些参数封装在一个map中,封装时使用的key就是参数的索引
    • Map<String, Object> map = new Hash<>();
    • map.put("1", value);
    • map.put("2", value);

解决办法一:使用@Param,告诉mybatis封装map的时候使用指定的key
public User getUserByIdAndName(@Param("id") Integer id, @Param("username") String username);
解决办法二:当参数属于我们业务POJO时,直接传递POJO
解决办法三:封装多个参数为map,直接传递

 

Oracle指定jdbcType

如果null被当作值来传递,mysql可以插入null,oracle不知道null是什么类型
所以Oracle数据库需要指定jdbcType
id = #{id, jdbcType=INT}

 

取值

mybatis中的两种取值方式:
#{属性名}:参数预编译的方式,参数的位置都是使用?替代,安全,可反正sql注入攻击
${属性名}:不是参数预编译方式,而是直接和sql语句进行拼串,不安全

select * from usertb where id=${id} and username=#{username}
select * from usertb where id=1 and username=?

 

查询返回list

如果返回的是集合,resultType中类型为集合中元素类型

<select id="getAllUsers" resultType="com.tang.bean.User">
	select * from usertb
</select>

  

返回结果封装为Map

返回单条记录

//单条记录封装为一个map,key为列名,value为值
public Map<String, Object> getUserById(Integer id);

  

<!--查询返回一个map-->
<select id="getUserById" resultType="map">
	select * from usertb where id=#{id}
</select>

  

返回多条记录

//多条记录封装为一个map,key为这条记录的主键,value为封装好的记录对象
//把查询的记录的id作为key封装一条记录
@MapKey("id")
public Map<Integer, User> getAllUsers();

  

<!--查询多个返回一个map,注意:resultType的值必须为"com.tang.bean.User",否则map不会将一条记录对象封装为User-->
<select id="getAllUsers" resultType="com.tang.bean.User">
	select * from usertb
</select>

  

resultMap自定义封装规则

默认mybatis自动封装结果集:按照列名和属性名一一对应的规则(注意:数据库不区分大小写)

如果列名和属性名不一一对应:

(1)开启驼峰命名规则(aaa_bbb映射为aaaBbb)

 

(2)起别名

<mapper namespace="com.tang.dao.UserDao">
	<select id="getUserById" resultType="com.tang.bean.User">
		select id,username myname,passwod mypassword,gender mygender from usertb where id=#{id}
	</select>
</mapper>

  

(3)resultMap自定义封装规则

<mapper namespace="com.tang.dao.UserDao">
	<select id="getUserById" resultMap="myuser">
		select * from usertb where id=#{id}
	<select>
	<!--自定义结果集(resultMap):自己定义每一列数据和JavaBean的映射规则
	       type:指定为哪个JavaBean自定义封装规则,值为全类名
	       id:resultMap的唯一标识
	-->
	<resultMap type="com.tang.bean.User" id="myuser">
		<!--指定主键列的对应规则
		      column:指定哪一列是主键列
		      property:指定JavaBean的哪个属性封装该列数据
		-->
		<id property="id" column="id"/>
		<!--普通列-->
		<result property="myname" column="username"/>
		<result property="mypassword" column="password"/>
		<result property="mygender" column="gender"/>
	</resultMap>
</mapper>

  

动态SQL

if标签

test:编写判断条件

<mapper namespace="com.tang.dao.UserDao">
	<select id="getUserByCondition" resultMap="myuser">
		select * from usertb where
		<if test="id!=null">
			id > #{id}
		</if>
		<if test="username != null and username.equals("")">
			and username like #{username}
		</if>
	</select>
</mapper>

  

trim标签

作用:截取字符串

prefix:为下面的sql整体添加一个前缀
prefixOverrides:删除整体字符串前面多余的字符
suffix:为下面的sql整体删除一个前缀
suffixOverrides:删除整体字符串后面多余的字符

<mapper namespace="com.tang.dao.UserDao">
	<select id="getUserByCondition" resultMap="myuser">
		select * from usertb 
		<trim prefix="where" prefixOverrides="and" suffixOverrides="and">
			<if test="id!=null">
				id > #{id}
			</if>
			<if test="username != null and username.equals("")">
				and username like #{username}
			</if>
		</trim>
	</select>
</mapper>

  

foreach标签

collection:指定要遍历的集合的key
open:以什么开始
close:以什么结束
item:变量名,每次遍历出来的元素起一个变量名以方便引用
separator:每次遍历的元素的分隔符
index:索引
如果遍历的是一个list,index保存当前遍历的元素的索引,item保存当前遍历的元素的值
如果遍历的是一个map,index保存当前遍历的元素的key,item保存当前遍历的元素的值

public List<User> getUserByIdIn(@Param("ids") List<Interger> ids);

  

<mapper namespace="com.tang.dao.UserDao">
	<select id="getUserByCondition" resultMap="myuser">
		select * from usertb where id IN
		<foreach collection="ids" open="(" close=")" separator="," item="id_item">
			#{id_item}
		</foreach>
	</select>
</mapper>

  

set标签

set标签去除可能多余的 ,

<mapper namespace="com.tang.dao.UserDao">
	<update id="updateUser">
		update usertb set 
		<set>
			<if test="username!=null and !name.equals("")">
				username=#{username},
			</if>
			<if test="password!=null and !password.equals("")">
				username=#{password},
			</if>
			<if test="permission!=null">
				permission=#{permission}
			</if>
		</set>
		<where>
			id=#{id}
		</where>
	</update>
</mapper>

  

 

缓存

缓存是一般的ORM框架都会提供的功能,目的是提升查询的效率和减少数据库的压力

缓存有关设置

  • 全局setting的cacheEnable:配置二级缓存的开关
  • select标签的useCache属性:配置这个select是否使用二级缓存
  • sql标签的flushCache属性:增删改默认flushCache=true,sql执行后会同时清空一级和二级缓存,查询默认flushCache=false
  • sqlSession.clearCache():只是用来清除一级缓存
  • 当在某一个作用域进行了 C/U/D 操作后,默认该作用域下所有select中的缓存将被clear

 

一级缓存

一级缓存也叫本地缓存,mybatis的一级缓存是在会话(SqlSession)层面进行缓存的。

注意:mybatis的一级缓存是默认开启的,不需要任何的配置

一级缓存失效的几种情况:

  • 不同的SqlSession对象,使用不同的一级缓存(每个SqlSession都有自己的Map存储数据)
  • SqlSession对象第一次执行该sql语句
  • 只要执行一次增删改操作,缓存就会被清空
  • 手动清空缓存 sqlSession.clearCache();

二级缓存

二级缓存是用来解决一级缓存不能跨会话共享的问题,范围是namespace级别的,可以被多个SqlSession共享(只要是同一个接口里面的相同方法,都可以共享)。如果使用了二级缓存,那么mybatis查询数据的顺序是:二级缓存->一级缓存->数据库

注意:二级缓存默认不开启,需要手动配置。SqlSession关闭或提交之后,一级缓存的数据会放在二级缓存中(即只有SqlSession关闭或提交之后二级缓存中才会有数据)

使用步骤:

  1. 全局配置文件中开启二级缓存
  2. 需要使用二级缓存的映射文件处(.xml文件)使用cache配置缓存<cache/>

注意:POJO需要实现Serializable接口

<!--开启全局缓存开关-->
<setting name="cacheEnabled" value="true"/>

  

<mapper namespace="com.tang.dao.UserDao">
    <cache/>
    ........
</mapper>

  

整合第三方缓存

整合ehcache

  1. 导包

     

     

  2. ehcache工作要有一个配置文件,文件名叫 ehcache.xml,放在类路径的根目录下
  3. 在mapper.xml中配置使用自定义的缓存

 

posted @ 2021-04-18 13:56  455994206  阅读(60)  评论(0)    收藏  举报