胡豆秆

个人博客

欢迎来到我的个人博客~


MyBatis的基本使用



MyBatis

​ MyBatis 是支持普通 SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Ordinary Java Objects,普通的 Java对象)映射成数据库中的记录。

​ 每个MyBatis应用程序主要都是使用SqlSessionFactory实例的,一个SqlSessionFactory实例可以通过SqlSessionFactoryBuilder获得。SqlSessionFactoryBuilder可以从一个xml配置文件或者一个预定义的配置类的实例获得。

配置文件

Spring集成MyBatis(数据源使用druid)配置文件 applicationContext.xml。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

	<!-- 开启注解扫描 -->
	<context:component-scan base-package="com.hu" />

	<!-- 配置数据源 -->
	<bean id="dataSource"
		class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
		destroy-method="close">
		<!-- ”连接“的基本属性 -->
		<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatisdemo?useUnicode=true&amp;characterEncoding=utf-8" />
		<property name="username" value="root" />
		<property name="password" value="123456" />
		<!-- 连接池属性 -->
		<!-- 初始化连接池个数 -->
		<property name="initialSize" value="5" />
		<!--  最大连接池个数 -->
		<property name="maxActive" value="20" />
		<!-- 配置获取连接等待超时的时间,单位毫秒 -->
		<property name="maxWait" value="60000" />
		<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
		<property name="minEvictableIdleTimeMillis" value="300000" />
		<property name="keepAlive" value="true" />
		<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
		<property name="timeBetweenEvictionRunsMillis" value="-1" />
		<!-- 最小连接池个数 -->
		<property name="minIdle" value="20" />
<!-- 		<property name="removeAbandoned" value="true" />
		<property name="removeAbandonedTimeout" value="180" />
		<property name="logAbandoned" value="true" /> -->
		<!-- 申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 -->
		<property name="testWhileIdle" value="true" />
		<!-- 用来检测连接是否有效的sql,要求是一个查询语句 -->
		<!-- 如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用 -->
		<property name="validationQuery" value="SELECT 1" />
		<!-- 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 -->
		<property name="testOnBorrow" value="false" />
		<!-- 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 -->
		<property name="testOnReturn" value="false" />
		<!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->
		<property name="poolPreparedStatements" value="true" />
		<!-- 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。-->
		<!-- 在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100 -->
		<property name="maxPoolPreparedStatementPerConnectionSize" value="20" />
		<!-- 通过别名的方式配置扩展插件,多个英文逗号分隔 -->
		<!-- 监控统计用的filter:stat -->
		<!-- 日志用的filter:log4j -->
		<!-- 防御sql注入的filter:wall -->
		<property name="filters" value="stat,wall,log4j" />
		<!-- 通过connectProperties属性来打开mergeSql功能;慢SQL记录 -->
		<property name="connectionProperties"
			value="druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000" />
		<!-- 合并多个DruidDataSource的监控数据 -->
		<!-- <property name="poolPreparedStatements" value="true" /> -->
	</bean>

	<!-- 会话工厂sqlSessionFactoryBean -->
	<bean id="sqlSessionFactory"
		class="org.mybatis.spring.SqlSessionFactoryBean">
		<!-- 数据源 -->
		<property name="dataSource" ref="dataSource"></property>
		<!-- 别名 -->
		<property name="typeAliasesPackage"
			value="com.hu.pojo"></property>
		<!-- sql映射文件路径 -->
		<property name="mapperLocations"
			value="classpath:mapper/*Mapper.xml"></property>
	</bean>

	<!-- 自动扫描对象关系映射 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<!--指定会话工厂,如果当前上下文中只定义了一个则该属性可省去 -->
		<property name="sqlSessionFactoryBeanName"
			value="sqlSessionFactory"></property>
		<!-- 指定要自动扫描接口的基础包,实现接口 -->
		<property name="basePackage"
			value="com.hu.mapper"></property>
	</bean>

	<!-- 声明式事务管理 -->
	<!--定义事物管理器,由spring管理事务 -->
	<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!--支持注解驱动的事务管理,指定事务管理器 -->
	<tx:annotation-driven
		transaction-manager="transactionManager" />

	<!-- aspectj支持自动代理实现AOP功能 -->
	<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
</beans>

在配置文件中,需要指定Mapper接口和Mapper.xml文件的位置(包名).

Mapper

传值

UserMapper.java

public interface UserMapper {
	//封装对象
	int insert(@Param("user")User user);
	//集合
	int insertList(@Param("list")List<User> list);
	//单个String
	List<User> selectList(String condition);
    //Map对象
    int method1(Map<String, Object> map);
}

Mapper接口传参到UseMapper.xml的方式主要有几种:

  1. 单个基本数据类型或String类型的参数(如:id),xml文件中直接使用#{}或${}引用。
  2. 多个参数,使用@Param(““)注解分辨(如:id,name),xml中使用#{} #{}或${} ${}引用。
  3. 封装对象(单个或多个),使用@Param(““)注解标明,xml中使用对象.属性引用(如:#{user.id} ${user.name})。若想直接使用#{属性}或${属性}取值,则在Mapper接口中传入对象时,不能使用@Param(““)注解标注(否则会造成参数不匹配错误,导致操作失败)。
  4. Map对象,使用Map对象无需使用@Param(““)注解。xml中使用对象.属性引用(如:#{wang.id} ${li.name})

取值

UserMapper.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.hu.mapper.UserMapper">
	<insert id="insert">
		insert into user(username,password) values(#{user.username},#{user.password});
		<!-- insert into user(username,password) values("${user.username}","${user.password}") -->
	</insert>
    <insert id="insertList">
		insert into user(username,password) values
		<foreach collection="list" item="user" separator="," index="index">
			(#{user.username},#{user.password})
		</foreach>
	</insert>
    <select id="selectList" resultType="user">
		select * from user
		<if test="condition != null and condition != ''">
			where username = #{condition}
		</if>
	</select>
    <insert id="method1">
		insert into user(username,password)
		values(#{li.username},#{li.password}),
		(#{wang.username},#{password})
	</insert>
</mapper>

在xml文件中,使用 #{}${} 取参数值。它们的主要区别是:

${} 直接将参数值(原封不动的)放到SQL语句的对于位置。

#{} 会根据参数值的类型,自动加上""。若取得的参数是String、char类型,会自动在该参数前后加上"

<!--接口传入 id = 1,username = "hu" -->
<!--使用#{} -->
select * from user where id = #{id} and username = #{username}
<!-- 该语句等价于 -->
select * from user where id = 1 and username = "hu"
<!--使用${} -->
select * from user where id = ${id} and username = "${username}
<!-- 该语句等价于 -->
select * from user where id = 1 and username = "hu"

​ 使用 ${} 并不会自动添加 "" ,需要自己手动添加(若没有手动添加,在遇到String或char类型参数时会出错)。在使用模糊查询时,不能使用#{}#{} 是将内部的值(即使拼接后是一条语句)都作为一个参数,所以使用 #{} 可以防止SQL注入。

<!--接口传入 username = "hu" -->
<!--模糊查询 -->
<!--使用#{} -->
select * from user where username like "%#{}%"
<!-- 该语句等价于 -->
select * from user where username like "%"hu"%"
<!-- 执行会出错 -->
<!--使用${} -->
select * from user where username like "%${}%"
<!-- 该语句等价于 -->
select * from user where username like "%hu%"

标签

定义SQL语句

<sql>

​ 用来定义常用sql语句,配合<include>标签使用。

<include>

​ 引用定义好的sql语句。

<sql id="selectAll">select *</sql>
	
<select id="select" resultType="user">
    <include refid="selectAll"/>
    from user where id = #{id}
</select>

<insert>

​ 用来定义INSERT插入语句。默认返回int值(该条语句执行后影响的行数)。

<insert id="insert">
    insert into user(username,password) values(#{user.username},#{user.password});
</insert>

<update>

​ 用来定义UPDATE更新语句。默认返回int值(该条语句执行后影响的行数)。

<update id="update">
update user set password = #{password}
</update>

<delete>

​ 用来定义DELETE删除语句。默认返回int值(该条语句执行后影响的行数)。

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

<select>

​ 用来定义SELECT查询语句。需要指定 resultTyperesultMap 属性值。

<select id="select" resultType="user">
    select * from user where id = #{id}
</select>

属性:

parameterType:传给此语句的参数的全路径名或别名 例:com.hu.pojo.User或user

resultType:语句返回值类型或别名(映射配置文件中会话工厂配置的类型别名)。

resultMap:语句返回值类型或别名(自定义对象属性加载,如需查询对象中包含了别的对象或数组,需使用resultMap)。

定义返回类型

<resultMap>

​ 建立SQL查询结果字段与实体属性的映射关系信息;将结果集中的列与java对象中的属性对应起来并将值填充进去。resultMap: type association:javaType collection:ofType

<resultMap id="userMap" type="user">
    <id property="id" column="u_id" />
    <result property="username" column="u_username" />
    <result property="password" column="u_password" />
    <association property="role" javaType="role">
        <id property="id" column="r_id" />
        <result property="name" column="r_name" />
        <collection property="menus" ofType="menu">
            <id property="id" column="m_id" />
            <result property="name" column="m_name" />
        </collection>
    </association>
</resultMap>

<select id="selectUser" resultMap="userMap">
    select u.id as u_id,u.username as u_username,u.password as u_password,
    r.id as r_id,r.name as r_name,
    m.id as m_id,m.name as m_name
    from user u
    left join user_role ur
    on u.id = ur.user_id
    left join role r
    on r.id = ur.role_id
    left join role_menus rm
    on rm.role_id = r.id
    left join menu m
    on m.id = rm.menu_id
</select>

属性:

id:定义的resultMap的id,用于引用。

type:语句返回值类型或别名(映射配置文件中会话工厂配置的类型别名)。

<id>

id的唯一作用就是在嵌套的映射配置时判断数据是否相同,当配置id标签时,MyBatis只需要逐条比较所有数据中id标签字段值是否相同即可,可以提高处理效率。property对应Java对象的属性,column对象查询集中的列名。

<result>

​ 用于将查询结果集和Java对象的属性一一映射起来,将结果集中的列赋值给对应的对象属性。property对应Java对象的属性,column对象查询集中的列名。没有配置result的属性不会被赋值。

<association>

​ 与result标签类似,用于映射Java对象中的单一对象属性(复杂类型属性)。property对应该单一对象属性的名称;javaType对应该对象属性的Java类型(类似于select标签的type属性)。

<collection>

​ 与collection标签类似,用于映射Java对象中的集合属性(如List)。property对应该集合属性的名称;ofType对应该集合属性中的Java类型(类似于association标签的javaType属性)。

SQL语句动态拼接

<foreach>

​ foreach标签主要用于遍历集合,构建in条件语句或者批量操作语句。他可以在sql中对集合进行迭代。

<insert id="insertList">
    insert into user(username,password) values
    <foreach collection="list" item="user" separator="," index="index">
        (#{user.username},#{user.password})
    </foreach>
</insert>

属性:

collection:表示迭代集合的名称,可以使用@Param注解指定,该参数为必选。

item:表示本次迭代获取的元素,若collection为List、Set或者数组,则表示其中的元素;若collection为map,则代表key-value的value,该参数为必选。

open:表示该语句以什么开始,最常用的是左括弧 ( ,注意:mybatis会将该字符拼接到整体的sql语句之前,并且只拼接一次,该参数为可选项。

close:表示该语句以什么结束,最常用的是右括弧 ) ,注意:mybatis会将该字符拼接到整体的sql语句之后,该参数为可选项。

separator:mybatis会在每次迭代后给sql语句加上separator属性指定的字符,该参数为可选项。

index:用于获取当前迭代的位置。在list、Set和数组中,index表示当前迭代的位置,在map中,index代指是元素的key,该参数是可选项。

<if>

​ if标签通常用于WHERE语句中,通过判断参数值来决定是否执行其中的语句, 他也经常用于UPDATE语句中判断是否更新某一个字段,还可以在INSERT语句中用来判断是否插入某个字段的值。

<select id="selectList" resultType="user">
    select * from user
    <if test="condition != null and condition != ''">
        where username like "%${condition}%"
    </if>
</select>

属性:

test:必填。该属性值是一个判断表达式,一般只用true或false作为结果。

<choose>

​ 按顺序判断when中的条件出否成立,如果有一个成立,则choose结束。当choose中所有when的条件都不满则时,则执行 otherwise中的sql。类似于Java 的switch 语句,choose为switch,when为case,otherwise则为default。

<select id="selectChoose" resultType="user">
    select * from user
    <choose>
        <when test="name != null and name != ''">
            where username = #{name}
        </when>
        <otherwise>
            where password = "5514"
        </otherwise>
    </choose>
</select>

<when>

​ 与if标签类似,当 when 中的条件满足的时候就输出其中的内容。当 when 中有条件满足的时候,就会跳出 choose,即所有的 when 和 otherwise 条件中,只有一个会输出,

<otherwise>

​ 当choose标签中的所有when标签都不满足条件时,执行otherwise中的内容。

格式化SQL语句

<where>

​ where 元素的作用是会在写入 where 元素的地方输出一个 where;如果所有的条件都不满足就会查出所有的记录;如果标签返回的内容是以 AND 或OR 开头的,则它会自动剔除掉(防止造成 where and 或者 where or 语法错误)。

<select id="selectWhere" resultType="user">
    select * from user
    <where>
        <if test="username != null and username != ''">
            username = #{username}
        </if>
        <if test="password != null and password != ''">
            and password = #{password}
        </if>
    </where>
</select>

<set>

​ 当 update 语句中没有使用 if 标签时,如果有一个参数为 null,都会导致错误。当在 update 语句中使用if标签时,如果前面的if没有执行,则或导致逗号多余错误。使用set标签可以将动态的配置 SET 关键字,并剔除追加到条件末尾的任何不相关的逗号。使用 if+set 标签修改后,若某一条if标签中的test不满足,则该条if标签中的语句不会执行。

<update id="updateSet">
    update user
    <set>
        <if test="username != null and username != ''">
            username = #{username},
        </if>
        <if test="password != null and password != ''">
            password = #{password},
        </if>
    </set>
    where id = #{id}
</update>

​ 上述例子中,若两个if标签都不满足,则会造成语句错误(update user where id = ?);

<trim>

​ trim标签是一个格式化的标签,可以完成set或where标签的功能。与where和set标签类似,会根据prefixOverrides和suffixOverrides属性自动完成前缀和后缀的去除。

<select id="selectTrim" resultType="user">
    select * from user
    <trim prefix="where" prefixOverrides="and|or">
        <if test="username != null and username != ''">
            and username = #{username}
        </if>
        <if test="password != null and password != ''">
            or password = #{password}
        </if>
    </trim>
</select>

<update id="updateTrim">
    update user
    <trim prefix="set" suffixOverrides=",">
        <if test="username != null and username != ''">
            username = #{username},
        </if>
        <if test="password != null and password != ''">
            password = #{password},
        </if>
    </trim>
    where id = #{id}
</update>

属性:

​ prefix:前缀覆盖并增加其内容

​ suffix:后缀覆盖并增加其内容

​ prefixOverrides:前缀判断的条件

​ suffixOverrides:后缀判断的条件

打赏一个呗

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦