文章目录
- MyBatis框架
- 概要
- MyBatis的使用
- 其他配置
- 动态SQL语句条件查询
- 关联查询
- 多形参
- 传递列名
- 存储过程调用
MyBatis框架
概要
MyBatis工作在数据访问层,此时的数据访问层就可以只编写 映射器接口 和 映射xml文件
使用场景:JavaSE、JavaEE(JavaWeb)
- 映射器接口:供业务逻辑层使用,接口中根据需要定义方法,MyBatis框架负责创建实现这些接口的实例对象。接口命名以Mapper结尾,如:
ProductMapper
- 映射xml文件:其中包含了与映射器接口中的方法一一对应的SQL语句,且映射xml文件与映射器接口同名,例如:
ProductMapper.xml
- 核心xml配置文件:配置数据库连接参数以及MyBatis框架运行时参数
通过API类加载配置文件和映射器接口类,最后就可以在MyBatis中使用实例化的接口对象
- 应用程序通过org.apache.ibatis.session.SqlSession接口与MyBatis框架进行交互
对象 | 重量级 | 使用 |
---|---|---|
SqlSessionFactory对象 | 重量级对象 | 创建一次 |
SqlSession对象 | 轻量级对象 | 可多次创建 |
MyBatis的使用
- 导入相关的jar包
- 普通工程导入jar包时,直接复制粘贴到当前项目中。若使用IDEA,则还需手动添加到工程中。
- Maven工程导入jar包时,在
.pom
配置文件中的dependencies
元素下添加以下内容:
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency>
- 编写数据访问层的映射器接口和映射xml文件
- 映射器接口
package com.MyBatis.demo.Dao;
import com.MyBatis.demo.bean.ProductInfo;
import java.util.List;
import java.util.Map;
public interface ProductMapper {
ProductInfo getInfoById(Integer productId);
List<ProductInfo> findAllProducts(Map<String,String> map);
int saveInfo(ProductInfo productInfo);
List<ProductInfo> findByCondition(Map<String,Object> condition);
int updatePrdInfo(int[] ids);
void findInfoByProcedure(Map<String,Object> map);
}
- 映射xml文件
namespace
属性值为 映射器接口 的完整类名- 根元素
mapper
的子元素select
、update
、insert
、delete
的id
属性是映射xml文件对应的映射器接口的某个具体方法名 - 根元素
mapper
的子元素update
、insert
、delete
不使用resultType
属性,默认返回整数,代表该语句影响的记录条数 - 元素
insert
的子元素selectKey
表示查询主键,具有keyColumn
、keyProperty
、order
、resultType
属性,能将查询结果存进keyProperty
指明的java对象属性中属性 说明 keyColumn
主键对应的数据库列名 keyProperty
主键对应的java对象属性名 order
1. AFTER
父元素的SQL语句执行后执行
2.BEFORE
父元素的SQL语句执行前执行resultType
主键返回的结果类型 <selectKey keyColumn="product_id" keyProperty="productId" resultType="int" order="BEFORE"> select ifnull(max(product_id)+1,1) from products p </selectKey>
- 如果主键列是自增类型(auto_increment),元素
insert
可使用如下属性:<insert id="saveInfo" parameterType="ProductInfo" useGeneratedKeys="true" keyProperty="productId"> ··· </insert>
- 如果主键列是自增类型(auto_increment),元素
- 使用
sql
元素可定义可重用的sql片段,其中的id
属性可唯一标识被引用的片段。引用语句如下:<include refid="id"></include>
- 元素的
parameterType
、resultType
属性分别表示参数类型、返回类型,resultMap
属性表示结果类型映射(可重用)。 resultType
属性和resultMap
属性不能同时存在- 元素的
parameterType
、resultType
属性取值为自定义类的完整限定名或MyBatis预定义别名。- 若返回类型为列表类型或集合类型,则
resultType
属性设置为列表或集合中的元素类型 - MyBatis预定义别名如下:
别名 java类型 别名 java类型 别名 java类型 _byte byte byte Byte decimal BigDecimal _long long long Long bigdecimal BigDecimal _short short short Short object Object _int int int Integer map Map _integer int integer Integer hashmap HashMap _double double double Double list List _float float float Float arraylist ArrayList _boolean boolean boolean Boolean collection Collection string String date Date iterator Iterator
- 若返回类型为列表类型或集合类型,则
- 为解决
<
或>
在xml文件中的特殊语法,将包含<
或>
的SQL语句包含在<![CDATA[ ]]>
语句的空白处 - SQL语句中的占位符使用
#{ }
#{ }
与${ }
区别- 在映射xml文件根元素
mapper
的子元素select
、update
、insert
、delete
中的SQL语句对应于映射器接口中的方法- 若映射器接口方法的形参为基本类型,则占位符可表示该形参,例如:
#{id}
- 若映射器接口方法的形参为java对象,则占位符可表示该对象的属性,例如:
#{productId}
- 若占位符表示的值可能为
null
,则在占位符中添加指明jdbc
数据类型,例如:#{price,jdbcType=DECIMAL}
jdbc
数据类型与java
数据类型对应关系如下:jdbcTyppe javaType TINYINT byte SMALLINT short INTEGER int INTEGER INTEGER INTEGER long BIGINT long FLOAT float ERAL float NUMERIC double DOUBLE double FLOAT double VARCHAR string CHAR string LONGVARCHAR string CLOB string BINARY byte[] VARBINARY byte[] LONGVARBINARY byte[] ARRAY array BIT boolean BOOLEAN boolean NUMERIC java.math.BigDecimal DECIMAL java.math.BigDecimal DATE java.sql.Date TIME java.sql.Time TIMESTAMP java.sql.Timestamp BLOB Blob CLOB Clob DISTINCT mapping of underlying type STRUCT struct REF Ref DATALINK java.net.URL[color=red][/color] tinyint
长度为1,即类型为:tinyint(1)
查询时,该字段对应的Java类型为boolean
;- 将字段的java类型设置为Integer
- 在jdbcUrl添加参数:
tinyInt1isBit=false
(默认为true
) - 避免使用长度为1的
tinyint
类型字段存储数字格式的数据
- 在jdbcUrl添加参数:
- 若占位符表示的值可能为
- 若映射器接口方法的形参为基本类型,则占位符可表示该形参,例如:
- 在映射xml文件根元素
resultMap
元素的type
属性使用类的完整限定名,也可以使用在核心配置文件Configuration.xml
中已定义过的简单别名resultMap
元素的子元素result
、id
(映射数据库主键)的column
属性表示SQL语句在数据库中对应的列名,而property
属性则表示的是java对象中的字段属性- 其他配置
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.MyBatis.demo.Dao.ProductMapper">
<sql id="sql1">
SELECT p.`product_id`,p.`name`,p.`product_type_id`,p.`price`,p.`description`
FROM products p
</sql>
<select id="getInfoById" parameterType="int" resultMap="mp1">
<![CDATA[SELECT p.`product_id`,p.`name`,p.`product_type_id`,p.`price`,p.`description` FROM products p WHERe p.`product_id`=#{productId}]]>
</select>
<select id="findAllProducts" parameterType="map" resultMap="mp1">
<include refid="sql1"></include>
ORDER BY ${colName}
</select>
<select id="findByCondition" parameterType="map" resultMap="mp1">
<include refid="sql1"></include>
<where>
<if test="prdName!=null">p.`name` like CONCAt('%',#{prdName},'%')</if>
<if test="lowPrice!=null"><![CDATA[AND p.`price`>=#{lowPrice}]]></if>
<if test="highPrice!=null"><![CDATA[AND p.`price`<=#{highPrice}]]></if>
<if test="typeId!=null">AND p.`product_type_id`=#{typeId}</if>
</where>
</select>
<update id="updatePrdInfo" parameterType="_int[]">
UPDATE products p SET p.`product_type_id`=3 WHERe p.`product_id` IN
<foreach collection="array" item="prdId" open="(" close=")" separator=",">
#{prdId}
</foreach>
</update>
<insert id="saveInfo" parameterType="productInfo">
<selectKey keyColumn="product_id" keyProperty="productId" resultType="int" order="BEFORE">
select ifnull(max(product_id)+1,1)
from products p
</selectKey>
INSERT INTO products
VALUE(
#{productId},
#{proTypeId,jdbcType=INTEGER},
#{productName},
#{proDescription,jdbcType=VARCHAR},
#{price,jdbcType=DECIMAL})
</insert>
<select id="findInfoByProcedure" parameterType="map" statementType="CALLABLE">
CALL pr_get_prd_info(#{prdId},
#{prdName,mode=OUT,jdbcType=VARCHAR},
#{typeId,mode=OUT,jdbcType=INTEGER},
#{desc,mode=OUT,jdbcType=VARCHAR},
#{price,mode=OUT,jdbcType=FLOAT})
</select>
<resultMap type="productInfo" id="mp1">
<id column="product_id" property="productId"></id>
<result column="product_type_id" property="proTypeId"></result>
<result column="name" property="productName"></result>
<result column="description" property="proDescription"></result>
<result column="price" property="price"></result>
</resultMap>
</mapper>
- 编写核心配置文件Configuration.xml
- 主要配置数据库的连接参数和映射xml文件路径
-
使用
typeAliases
元素设置类的简单名(仅首字母小写)取代类的全限定名,如下:<typeAliases> <typeAlias type="com.MyBatis.demo.bean.ProductInfo" alias="productInfo"></typeAlias> <typeAlias type="com.MyBatis.demo.bean.ProductTypeInfo" alias="productTypeInfo"></typeAlias> </typeAliases>
-
transactionManager : 事务管理器
类型 描述 JDBC MyBatis默认使用的提交和回滚管理事务 MANAGED 由容器管理事务 如:Spring -
dataSource :配置数据源
三种数据源UNPOOLED
、POOLED
、JNDI
UNPOOLED : 非池化 不采用连接池 的数据源 仅需配置driver url username password| POOLED : 采用连接池的数据源 除配置driver url username password外 还可配置以下属性: poolMaximumActiveConnections 最大活动连接数。默认值:10 poolMaximumIdleConnections 最大空闲连接数 poolMaximumCheckoutTime 池中连接的检查时间。默认值 20000毫秒(20秒) JNDI : 从环境中获取数据源
-
- 主要配置数据库的连接参数和映射xml文件路径
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<typeAlias type="com.MyBatis.demo.bean.ProductInfo" alias="productInfo"></typeAlias>
<typeAlias type="com.MyBatis.demo.bean.ProductTypeInfo" alias="productTypeInfo"></typeAlias>
</typeAliases>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/store?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<property name="poolMaximumIdleConnections" value="1"/>
<property name="poolMaximumActiveConnections" value="5"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/MyBatis/demo/Dao/ProductMapper.xml"></mapper>
</mappers>
</configuration>
- 编写代码加载MyBatis核心类,解析核心配置文件
- 在Configuration.xml文件中,environments下可配置多套环境,但一个SqlSessionFactory实例只对应一种环境
- 创建SqlSessionFactory实例时可指定环境
- 默认环境
SqlSessionFactoryBuilder().build(reader);
- 指定环境id
SqlSessionFactoryBuilder().build(Reader reader,String id);
- 默认环境
String rs = "com/MyBatis/demo/Configuration.xml";
Reader reader = Resources.getResourceAsReader(rs);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
- 创建SqlSession实例并通过它获取映射器接口实例
- SqlSession默认非自动提交事务,可手动提交,也可设置自动提交
SqlSession session = sqlSessionFactory.openSession();
//手动提交
session.commit();
//设置自动提交
SqlSession openSession(boolean autoCommit);
//获取映射器接口Mapper实例
UserMapper productMapper = session.getMapper(ProductMapper.class);
- 调用映射器接口中的方法执行数据处理
ProductInfo productInfo = productMapper.getInfoById();
- 关闭SqlSession
session.close();
其他配置
关于映射xml文件的配置
动态SQL语句条件查询
在映射xml文件中,根元素
mapper
的子元素select
、update
、insert
、delete
都可使用动态SQL语句进行条件查询
<where>
元素- 包含子元素
<if>
,以if
元素的test
属性内容作为判断条件动态的生成条件查询的SQL语句 - 若
if
元素的test
属性的判断条件有一个是成立的,则在where
元素之前的SQL语句后面插入一个where
- 若
test
属性的判断条件成立,则将if
元素包含的SQL语句片段追加到已有的SQL语句片段上 - 若追加到已有SQL语句片段上的内容以
AND
或OR
开头,则将去掉AND
或OR
示例如下:<where> <if test="prdName!=null">p.`name` like CONCAt('%',#{prdName},'%')</if> <if test="lowPrice!=null"><![CDATA[AND p.`price`>=#{lowPrice}]]></if> <if test="highPrice!=null"><![CDATA[AND p.`price`<=#{highPrice}]]></if> <if test="typeId!=null">AND p.`product_type_id`=#{typeId}</if> </where>
<where>
元素还含有<choose>
子元素,<choose>
子元素下含有when
、otherwise
子元素- 若遇到
when
元素的test
属性判断条件成立,则仅将该when
元素包含的SQL语句片段追加到已有的SQL语句片段之后 - 若所有的
when
元素的test
属性判断条件都不成立,则将otherwise
元素中获得的SQL语句片段追加到已有的SQL语句片段之后otherwise
元素下包含子元素if
示例如下:
<where> <choose> <when test="productId!=null">product_id=#{productId}</when> <otherwise> <if test="productName!=null">and name like ···</if> <if test="typeId!=null">and ···</if> </otherwise> </choose> </where>
- 若遇到
- 包含子元素
<foreach>
元素collection
属性表示取值参数的数据类型,可以是集合或数组(array)、列表(list)item
属性表示用来指定迭代元素的变量名open
属性表示迭代元素在SQL语句中的起始符号close
属性表示迭代元素在SQL语句中的结束符号separator
属性表示迭代元素之间的分隔符
示例如下:
<update id="updatePrdInfo" parameterType="_int[]"> UPDATE products p SET p.`product_type_id`=3 WHERe p.`product_id` IN <foreach collection="array" item="prdId" open="(" close=")" separator=","> #{prdId} </foreach> </update>
关联查询
查询时同时读取关联数据,只能使用
<resultMap>
元素和resultMap
属性进行配置,不能使用resultType
属性
resultMap
元素中与关联查询相的子元素有:association
、collection
association
元素- 关联数据类型为java对象
property
属性表示关联数据对象在结果映射对象中的属性名javaType
属性表示关联数据对象在java中的数据类型名- 关联数据对象的属性封装使用
id
、result
子元素
示例如下:<resultMap id="map2" type="productInfo"> <id column="product_id" property="productId"></id> <result column="name" property="productName"></result> <result column="description" property="proDescription"></result> <result column="price" property="price"></result> <association property="typeInfo" javaType="productTypeInfo"> <id column="product_type_id" property="typeId"></id> <result column="type_name" property="typeName"></result> </association> </resultMap>
collection
元素- 关联数据类型为集合
property
属性表示关联集合在结果映射对象中的属性名javaType
属性表示关联集合在java中的数据类型名(简单名或全限定名)ofType
属性表示关联集合中的元素在java中的数据类型(简单名或全限定名)- 关联集合的元素存放使用
id
、result
子元素
示例如下:<resultMap id="mapl" type="productTypeInfo"> <id column="product_type_id" property="typeId"></id> <result column="type_name" property="typeName"></result> <collection property="products" javaType="java.util.Set" ofType="productInfo"> <id column="product_id" property="productId"></id> <result column="name" property="productName"></result> <result column="description" property="proDescription"></result> <result column="price" property="price"></result> </collection> </resultMap>
- 也可以直接使用
resultMap
属性对关联集合的元素进行存放
例如:<collection property="products" resultMap="rm3"/>
多形参
映射器接口方法传递多个形参时在xml配置中无需使用
parameterType
属性
- 在xml配置文件中使用占位符
#{ }
进行形参传递
故此以映射器接口中方法签名中形参出现的顺序在xml配置文件中分别使用#{arg0}
、#{arg1}
、#{arg2}
、#{arg3}
···表示- 如果参数可能为
null
,则需指明jdbc
数据类型
例如:
<insert id="saveInfo2"> INSERT INTO products VALUE( 0, #{arg1,jdbcType=INTEGER}, #{arg0}, #{arg2,jdbcType=VARCHAR}, #{arg3,jdbcType=DECIMAL}) </insert>
- 如果参数可能为
传递列名
#{ }
传递的是映射器接口方法中的形参
经过MyBatis转换为占位符?
${ }
传递的是以形参表示的数据库中的列名
经过MyBatis直接替换为数据库中的列名
也可在${ }
内传入一段SQL语句片段,例如:${ORDER BY p.price}
- 传递列名的形参类型为自定义类或Map对象
例如:<select id="findAllProducts" parameterType="map" resultMap="mp1"> SELECT p.`product_id`,p.`name`,p.`product_type_id`,p.`price`,p.`description` FROM products p ORDER BY ${colName} </select>
- 传递列名的形参类型为自定义类或Map对象
存储过程调用
根元素
mapper
下子元素insert
、select
、delete
、update
均可调用存储过程通过子元素
insert
、select
、delete
、update
的statementType
属性指明SQL语句的类型
statementType
属性值有:CALLABLE
、PREPARED
、STATEMENT
statementType
属性默认属性值为:PREPARED
CALLABLE
对应jdbcCallableStatement
语句对象类型,表示SQL语句为存储过程调用PREPARED
对应jdbcPreparedStatement
语句对象类型,表示SQL语句为预编译语句STATEMENT
对应jdbcStatement
语句对象类型,表示SQL语句MySQL
中存储过程的创建和使用- 创建存储过程之前,使用
DELIMITER //
指明存储过程的结束符为//
- 存储过程创建完成使用
DELIMITER ;
恢复为SQL语句的结束符为;
DELIMITER
用以声明当前语句的结束符
BEGIN
表示存储过程的开始,END
表示存储过程的结束OUT
表示传出数据
IN
表示传入数据
INOUT
表示既传出也传入数据- 关键字
CALL
表示调用存储过程
示例如下:DELIMITER // create procedure pr_get_prd_info(p_prd_id Int,OUT p_prd_name varchar(30),OUT p_type_id int,OUT p_desc varchar(50),OUT p_price Float) BEGIN select product_type_id,name,description,price into p_type_id,p_prd_name,p_desc,p_price from products p where product_id=p_prd_id; END // DELIMITER ; CALL pr_get_prd_info(···)
- 创建存储过程之前,使用
- 在映射器接口中与调用存储过程相对应的方法返回类型为
void
实参类型应为封装的自定义类或Map
集合- 仅能实参传形参
- 在传递参数时,使用
mode
属性指明传递模式,jdbcType
指明jdbc
类型mode
属性传递模式的属性值有:OUT
表示传出数据IN
表示传入数据INOUT
表示既传出也传入数据
存储过程xml配置如下:
<select id="findInfoByProcedure" parameterType="map" statementType="CALLABLE">
CALL pr_get_prd_info(#{prdId},
#{prdName,mode=OUT,jdbcType=VARCHAR},
#{typeId,mode=OUT,jdbcType=INTEGER},
#{desc,mode=OUT,jdbcType=VARCHAR},
#{price,mode=OUT,jdbcType=FLOAT})
</select>
注意:
存储过程调用之前需确认是否授权
可在MySQL中授权
也可在SQLyog中的用户管理
->对象级别特权
中选择EXECUTE
、CREATE ROUTINE
、ALTER ROUTINE