1.MyBatis的SQL映射文件
1.1增删改查标签
<!--
标签属性:
id:identifier:唯一标识符,id值要和接口的方法名保持一致
parameterType:参数类型,该参数是可以省略的!
resultType:返回结果类型,和接口返回结果类型保持一致。
-->
<select id="getProductById" resultType="com.offcn.bean.Product">
select pid,p_name pName,color,price,description from product where pid= #{pid}
</select>
<insert id="saveProduct" >
insert into product(p_name,color,price,description) values(#{pName},#{color},#{price},#{description})
</insert>
<update id="updateProduct" >
update product set p_name = #{pName},price=#{price} where pid=#{pid}
</update>
<delete id="deleteProductByPid" >
delete from product where pid = #{pid}
</delete>
注意点:
*对于增删改标签,必须提交事务:
- 手动提交:sqlSession.commit()
- 自动提交: sqlSessionFactory.openSession(true)
测试代码:
@Test
public void testDelete() throws IOException {
SqlSession sqlSession = sqlSessionFactory.openSession(true);
ProductMapper mapper = sqlSession.getMapper(ProductMapper.class);
mapper.deleteProductByPid(15);
//4.关闭SqlSession对象
sqlSession.close();
}
1.2Sql片段
<!-- sql标签主要是做sql语句重用 -->
<sql id="productSql">
p_name,color,price,description
</sql>
引用即可:
<select id="getProductById" resultType="com.offcn.bean.Product">
select pid,<include refid="productSql"/> from product where pid= #{pid}
</select>
2.在sql语句中如何获取各种各样的参数
* 1.一个普通参数 : #{随便写}
* 2.多个【两个及两个以上】普通参数 : 给每个参数前面加一个@param,在sql语句的#{}里面用@Param注解的value值取
* 3.参数是一个POJO对象 : #{对象的属性名}
* 4.参数是一个Map : #{某个键}
* 4.参数是一个POJO对象列表【List、Collection】: #{list[下标]}或者 #{collection[下标]}或者 #{param注解[下标]}
* 5.参数是一个数组类型 : #{array【下标】}
* 6.参数是上面的任意组合 : {param注解的value值,再通过.或者下标的方式去属性值或者元素值}
3.MyBatis接口的各种各样的返回值
* 接口中各种各样的返回值:
* 1.基本数据类型:int,Integer、double、Double、long、Long、boolean
* select: 需要在mapper接口中声明返回值类型,并且SQL映射文件中声明resultType属性
* insert、update、delete:只需要在mapper接口中声明返回值类型即可,在对应的SQL映射文件中不用声明resultType属性
* 2.POJO对象
* 3.POJO对象列表:
* 4.Map集合:基本不用
* 一行:
* 多行:
3.1#{}与${}区别 [面试题]
#{}
:类似于我们JavaWeb部分学过的PrepareStatement对象,采用占位符,
以预编译的方式执行sql语句的,是Sql安全的,不存在sql漏洞问题。
${}
:类似于我们JavaWeb部分学过的statement对象,直接将参数拼接到sql语句中,
这种是存在sql漏洞问题。
实际开发中,一般都使用#{},但是在有些特殊情况下,就必须使用
,
比
如
获
取
表
名
、
排
序
字
段
、
l
i
k
e
模
糊
查
询
,
就
必
须
使
用
{}, 比如获取表名、排序字段、like模糊查询,就必须使用
,比如获取表名、排序字段、like模糊查询,就必须使用{}
3.2ResultMap标签
如果数据表的列名和pojo对象的属性名不对应时,怎么将表的列名映射到对象属性上?
一、起别名
二、在mybatis的全局配置文件中开启:mapUnderscoreToCamelCase=true
三、使用ResultMap标签
<!-- resultMap 可以完成表的列名和pojo对象的属性名的映射 -->
<resultMap type="com.offcn.bean.Product" id="getProductByIdResultMap">
<!-- id是用来映射主键的 -->
<id column="pid" property="pid"/>
<!-- result标签是用来映射其它普通字段的 -->
<result column="p_name" property="pName"/>
<result column="price" property="price"/>
<result column="color" property="color"/>
<result column="description" property="description"/>
</resultMap>
<!-- resultType属性和resultMap 有且只能有一个属性存在 -->
<select id="getProductById" resultMap="getProductByIdResultMap">
select pid,p_name,price,color,description from product where pid = #{pid}
</select>
resultMap作用:
1.字段映射
2.可以将表的关联关系直接映射pojo对象的关联关系。这个功能是resultType所不具
备的,resultType只能是处理单表映射。
4.关联关系映射
表与表之间关系:一对一、一对多、多对一、多对多
4.1x对一的关联关系映射
以多对一为例:讲解对一的关联关系映射
举例:员工对部门、订单项和订单
需求:在查询员工信息的时候,顺带着将该员工所属的部门信息查询查来。
4.1.1创建表
CREATE TABLE dept(
did INT PRIMARY KEY AUTO_INCREMENT COMMENT '部门id',
dept_name VARCHAR(30) NOT NULL COMMENT '部门名称'
)
CREATE TABLE emp(
eid INT PRIMARY KEY AUTO_INCREMENT COMMENT '员工id',
ename VARCHAR(30) NOT NULL COMMENT '员工名称',
did INT COMMENT '所属部门id',
FOREIGN KEY(did) REFERENCES dept(did)
)
4.1.2创建实体类
public class Dept {//提供属性的getter/setter方法
private Integer did;
private String deptName;
}
public class Employee {//提供属性的getter/setter方法
private Integer eid;
private String ename;
private Dept dept;
}
4.1.3创建接口和sql映射文件
public interface EmployeeMapper {
public Employee getEmployeeWithDeptByEid(Integer eid);
}
<?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.offcn.dao.EmployeeMapper">
</mapper>
4.1.4关联关系映射【三种解决方案】
第一种:给属性的属性赋值。【连缀】
<resultMap type="com.offcn.bean.Employee" id="getEmployeeWithDeptByEidResultMap">
<!-- 员工表数据的映射 -->
<id column="eid" property="eid"/>
<result column="ename" property="ename"/>
<!-- 部门表数据的映射 -->
<result column="did" property="dept.did"/>
<result column="dept_name" property="dept.deptName"/>
</resultMap>
<select id="getEmployeeWithDeptByEid" resultMap="getEmployeeWithDeptByEidResultMap">
SELECT e.eid,e.ename,e.did,d.`dept_name`
FROM emp e
LEFT JOIN dept d
ON e.`did` = d.`did`
WHERE e.eid = #{eid}
</select>
4.2x对多的关联关系映射[2种]
一对多:订单和订单项,部门和员工
多对多:老师和学生
以部门和员工为例,演示:
需求:在查询某个部门信息的时候,将该部门下的所有员工信息也查询出来。
4.2.1创建表
CREATE TABLE dept(
did INT PRIMARY KEY AUTO_INCREMENT COMMENT '部门id',
dept_name VARCHAR(30) NOT NULL COMMENT '部门名称'
)
CREATE TABLE emp(
eid INT PRIMARY KEY AUTO_INCREMENT COMMENT '员工id',
ename VARCHAR(30) NOT NULL COMMENT '员工名称',
did INT COMMENT '所属部门id',
FOREIGN KEY(did) REFERENCES dept(did)
)
4.2.2创建实体类
public class Dept {
private Integer did;
private String deptName;
private List<Employee> emps;//提供getter/setter方法
}
public class Employee { //提供getter/setter方法
private Integer eid;
private String ename;
}
4.2.3创建mapper接口和sql映射文件
public interface DeptMapper {
Dept getDeptWithEmpsByDid(Integer did);
}
<?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.offcn.dao.DeptMapper">
</mapper>
4.2.4关联映射[2种解决方案]
第一种:在resultlMap标签内部采用collection标签
<resultMap type="com.offcn.bean.Dept" id="getDeptWithEmpsByDidResultMap">
<id column="did" property="did"/>
<result column="dept_name" property="deptName"/>
<!-- 映射关联字段
collection:标签用于处理对多的关联关系
property:指定关联属性
ofType:指定集合中元素的数据类型
-->
<collection property="emps" ofType="com.offcn.bean.Employee">
<id column="eid" property="eid"/>
<result column="ename" property="ename"/>
</collection>
</resultMap>
<select id="getDeptWithEmpsByDid" resultMap="getDeptWithEmpsByDidResultMap">
SELECT d.`did`,d.`dept_name`,e.`eid`,e.`ename`
FROM dept d
LEFT JOIN emp e
ON e.`did`=d.`did`
WHERE d.`did` = #{did}
</select>
第二种:分步查询,resultMap标签内部采用collection标签
deptMapper.xml文件
<resultMap type="com.offcn.bean.Dept" id="getDeptWithEmpsByDidResultMap">
<id column="did" property="did"/>
<result column="dept_name" property="deptName"/>
<!-- 关联字段映射 -->
<collection property="emps" select="com.offcn.dao.EmployeeMapper.getEmpsByDid" column="did"></collection>
</resultMap>
<select id="getDeptWithEmpsByDid" resultMap="getDeptWithEmpsByDidResultMap">
SELECT d.`did`,d.`dept_name`
FROM dept d
WHERE d.`did` = #{did}
</select>
EmployeeMapper.xml
<select id="getEmpsByDid" resultType="com.offcn.bean.Employee">
SELECT e.eid,e.ename
FROM emp e
WHERE e.did= #{dddd}
</select>
补充:
多对多表的创建:
CREATE TABLE teacher(
tid INT PRIMARY KEY AUTO_INCREMENT,
tname VARCHAR(30) NOT NULL
);
CREATE TABLE student(
sid INT PRIMARY KEY AUTO_INCREMENT,
sname VARCHAR(30) NOT NULL
)
CREATE TABLE student_teacher(
sid INT,
tid INT,
PRIMARY KEY(sid,tid),
FOREIGN KEY(sid) REFERENCES student(sid),
FOREIGN KEY(tid) REFERENCES teacher(tid)
)
5.MyBatis动态SQL
• if:类似于javaweb部分的c:if标签,做判断使用
• choose (when, otherwise): 类似于java基础的switch…case多分支判断语句。
• trim (where, set):where标签代替where关键字、set标签代替set关键字
• foreach:类似于javaweb部分学过的c:foreach标签,遍历一个集合或者数组的
动态sql在mybatis的SQL映射文件中使用。
5.1If
需求:如果用户输入了价格,就按着价格查询,如果用户输入了产品名称,就按着产品名称查询,如果这两个条件都输入了,我们就用这两个条件一起查询。
<select id="getProductList" resultType="com.offcn.bean.Product">
select pid,p_name pName,price,color,description
from product
where
<if test="price >= 0">
price > #{price}
</if>
<if test="pName != null and pName != '' ">
and p_name like '%${pName}%'
</if>
<if test="pid != null">
and pid = #{pid}
</if>
</select>
注意点:
不要&&,用and,实在想用,用这些特殊字符的实体名称,可以参考
MyBatis的SQL映射文件不支持直接使用<【小于号】,要想使用可以借助于<![CDATA[SQL语句]]>
If标签这里存在bug,怎么解决?
两种解决方案:
第一种:在where后面加一个 1=1
第二种解决方案:将where关键字换成where标签,where标签相当于where关键字,并且where标签可以将where标签内部所有sql拼接完毕之后的最前面的and或者or关键字去掉。
5.2Where标签
<select id="getProductList" resultType="com.offcn.bean.Product">
select pid,p_name pName,price,color,description
from product
<where>
<if test="price > 0">
<![CDATA[price < #{price}]]>
</if>
<if test="pName != null and pName != '' ">
and p_name like '%${pName}%'
</if>
<if test="pid != null">
and pid = #{pid}
</if>
</where>
</select>
Where标签存在的问题是:只能将where内部拼接的sql语句最前面的and或者or关键字去除,并不能将where内部拼接的sql语句最后面的and或者or关键字去除。
5.3Trim
<!--
trim标签:
prefix:前缀,表示trim标签内部所有的sql拼接完毕之后,需要在最前面加的前缀
prefixOverrides:前缀覆盖,表示trim标签内部所有的sql拼接完毕之后,用指定的prefixOverrides值将前面多余的关键字去除。
suffix:后缀,表示trim标签内部所有的sql拼接完毕之后,需要在最后面加的后缀
suffixOverrides:后缀覆盖,表示trim标签内部所有的sql拼接完毕之后,用指定的suffixOverrides值将最后面多余的关键字去除。
-->
<select id="getProductList" resultType="com.offcn.bean.Product">
select pid,p_name pName,price,color,description
<trim prefix="from product where" suffixOverrides="and">
<if test="price > 0">
<![CDATA[price < #{price}]]> and
</if>
<if test="pName != null and pName != '' ">
p_name like '%${pName}%' and
</if>
<if test="pid != null">
pid = #{pid}
</if>
</trim>
</select>
5.4choose (when, otherwise)
需求:如果用户输入了产品的价格,就用价格查询,如果用户输入了产品的名称,就用名称查询,如果两个条件都带了,还是用价格查询
总结:choose(when、otherwise)它是有优先级的,只会走其中一个,一旦有满足条件的,执行完之后就退出了,不会执行后面的。
进行多分支判断:
<select id="getProductListWithChoose" resultType="com.offcn.bean.Product">
select pid,p_name pName,price,color,description
from product
where
<choose>
<when test="price > 0">
price > #{price}
</when>
<when test="pName != null and pName != '' ">
p_name like '%${pName}%'
</when>
<otherwise>
pid = #{pid}
</otherwise>
</choose>
</select>
5.5set
set标签是用来代替set关键字,可以将set标签内部最后面多出来的,【逗号】给去掉!
<update id="updateProduct">
update product
<set>
<if test="pName != null and pName != '' ">
p_name=#{pName},
</if>
<if test="price > 0">
price=#{price}
</if>
</set>
where pid=#{pid}
</update>
5.6foreach
批量查询:
<select id="getProductWithForeach" resultType="com.offcn.bean.Product">
select pid,p_name pName,price,color,description
from product
where pid in
<!-- foreach标签遍历集合或者数组
属性:
collection:表示要遍历的集合
item:表示将集合中的每个元素临时赋值给这个变量
separator:表示元素与元素之间的分隔符
open:当foreach标签遍历完集合或者数组之后,在拼接之后的sql最前面加的符号
close:当foreach标签遍历完集合或者数组之后,在拼接之后的sql最后面加的符号
index:表示该元素在集合中的索引值,一般不用
-->
<foreach collection="list" item="pid" separator="," open="(" close=")">
#{pid}
</foreach>
</select>
<select id="getProductWithForeachArray" resultType="com.offcn.bean.Product">
select pid,p_name pName,price,color,description
from product
where pid in
<foreach collection="array" item="pid" separator="," open="(" close=")">
#{pid}
</foreach>
</select>
批量插入:
<insert id="batchInsert">
INSERT INTO product(p_name,price,color,description) VALUES
<foreach collection="list" item="pro" separator=",">
(#{pro.pName},#{pro.price},#{pro.color},#{pro.description})
</foreach>
</insert>
批量删除:
6.MyBatis的运行流程
7.SSM整合
SSM:SpringMVC+Spring+MyBatis,简称SSM,
SSH: Struts2+Spring+Hibernate:简称SSH
整合效果:整合之后SpringMVC管理控制层,Spring管理Service,MyBatis管理Dao层。
具体步骤:
- 第一步:导入jar包:springmvc+spring+mybatis+mybatis-spring.jar+mysql/c3p0+jstl
- 第二步:在web.xml文件中配置spring的监听器【ContextLoaderListener】、springmvc的前
端控制器、两个Filter - 第三步:创建springmvc.xml并配置
扫描包【@Controller、@ControllerAdvice】
配置内部资源视图解析器
Mvc:default-servlet-handler标签
Mvc:anntotation-driven - 第四步:创建applicationContext.xml并配置
扫描包【除了加@Controller、@ControllerAdvice】
加载properties配置文件信息
配置数据源
配置数据源事务管理器
开启基于注解的事务支持
配置SqlSessionFactoryBean对象
DataSource:配置数据源
configLocation:加载MyBatis全局配置文件
配置MapperScannerConfigurer对象
BasePackage:指定Mapper接口所在的包 - 第五步:写测试代码,测试