面向接口编程与参数详解
使用getMapper()方法实现面向接口编程
JsrDao jsrDao = SqlSessionUtil.getSession().getMapper(JsrDao.class);
组织架构:
数据表
重点:
mapper文件里面的select标签的id值必须和接口里面的方法名称一致
mapper文件的命名空间必须是包名.接口名的形式,如:
<mapper namespace="com.mybatis_03.dao.JsrDao">
...
</mapper>
- 接口文件 JsrDao.java
package com.mybatis_03.dao;
import com.mybatis_03.domain.Jsr;
import com.mybatis_03.domain.pageParams;
import com.mybatis_03.vo.StuClassVo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* @author Nigori
* @date 2020/2/1
**/
public interface JsrDao {
List<Jsr> getAll();
public void save(Jsr j);
void update(Jsr j);
void delete(String a006);
/* 省略代码在下方分类中 */
}
- 映射文件 JsrDao.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映射文件-->
<mapper namespace="com.mybatis_03.dao.JsrDao">
<select id="getAll" parameterType="String" resultType="Jsr">
select * from tb_jsr
</select>
<insert id="save">
insert into tb_jsr(id,name,sex,age,tel,num,classroom) values(#{id},#{name},#{sex},#{age},#{tel},#{num},#{classroom})
</insert>
<update id="update">
update tb_jsr set name = #{name},sex = #{sex},age = #{age},tel = #{tel},num = #{num},classroom = #{classroom} where id = #{id}
</update>
<delete id="delete">
delete from tb_jsr where id = #{id}
</delete>
...
<!-- 为方便直观体现知识点的不同之处,省略代码在下方分类写 -->
</mapper>
- 测试类 Test_03.java
package com.mybatis_03.test_03;
import com.mybatis_03.dao.JsrDao;
import com.mybatis_03.domain.Jsr;
import com.mybatis_03.util.SqlSessionUtil;
import com.mybatis_03.vo.StuClassVo;
import java.util.List;
/**
* @author Nigori
* @date 2020/2/9
**/
public class Test_03 {
public static void main(String[] args) {
JsrDao jsrDao = SqlSessionUtil.getSession().getMapper(JsrDao.class);
//查询所有
/*List<Jsr> j = jsrDao.getAll();
System.out.println(j);*/
//添加操作
/*Jsr j = new Jsr();
j.setId("A009");
j.setName("tly");
j.setSex("女");
j.setAge(29);
j.setTel("159******");
j.setNum("459643");
j.setClassroom("B003");
jsrDao.save(j);
SqlSessionUtil.mybCommit(SqlSessionUtil.getSession());
SqlSessionUtil.mybClose(SqlSessionUtil.getSession());*/
//修改操作
Jsr j = new Jsr();
j.setId("A003");
j.setName("out");
j.setSex("女");
j.setAge(29);
j.setTel("133******");
j.setNum("459789");
j.setClassroom("B003");
jsrDao.update(j);
SqlSessionUtil.getSession().commit();
SqlSessionUtil.mybClose(SqlSessionUtil.getSession());
//删除操作
/*jsrDao.delete("A005");
SqlSessionUtil.mybCommit(SqlSessionUtil.getSession());
SqlSessionUtil.mybClose(SqlSessionUtil.getSession());*/
...
/* 省略代码在下方分类中 */
}
}
- 工具类 SqlSessionUtil.java
package com.mybatis_03.util;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
/**
* @author Nigori
* @date 2020/2/1
**/
public class SqlSessionUtil {
private SqlSessionUtil(){}
private static SqlSessionFactory sqlSessionFactory;
static{
String resource = "mybatis-config.xml";
InputStream inputStream = null;
try {
inputStream = Resources.getResourceAsStream(resource);
} catch (IOException e) {
e.printStackTrace();
}
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
/*
处理同一个事务,使用同一个SqlSession对象,ThreadLocal是线程存储类
所以,ThreadLocal作用为第一次使用SqlSession对象时是创建并存放的过程,后面使用SqlSession对象时为获取的过程
*/
private static ThreadLocal<SqlSession> t = new ThreadLocal<SqlSession>();
//取得SQLSession对象
public static SqlSession getSession(){
SqlSession session = t.get();
if(session==null){
session = sqlSessionFactory.openSession();
t.set(session);
}
return session;
}
//提交事务
public static void mybCommit(SqlSession session){
if(session!=null){
session.commit();
}
}
//关闭SQLSession对象
public static void mybClose(SqlSession session){
if(session!=null){
session.close();
//必须加,作用:剥离ThreadLocal中保存的SqlSession...[原因:线程池]
t.remove();
}
}
}
- pageParams.java
package com.mybatis_03.domain;
/**
* @author Nigori
* @date 2020/2/10
**/
public class pageParams {
private int start;
private int limit;
public int getStart() {
return start;
}
public void setStart(int start) {
this.start = start;
}
public int getLimit() {
return limit;
}
public void setLimit(int limit) {
this.limit = limit;
}
}
- StuClassVo.java
package com.mybatis_03.vo;
/**
* @author Nigori
* @date 2020/2/12
**/
public class StuClassVo {
private String cla;
private String sid;
private String teacher;
private String jsid;
private String name;
private String sex;
private int age;
private String tel;
private String num;
private String classroom;
@Override
public String toString() {
return "StuClassVo{" +
"cla='" + cla + '\'' +
", sid='" + sid + '\'' +
", teacher='" + teacher + '\'' +
", jsid='" + jsid + '\'' +
", name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
", tel='" + tel + '\'' +
", num='" + num + '\'' +
", classroom='" + classroom + '\'' +
'}';
}
...
/* setter and getter */
}
参数传递类型 parameterType
<select id="select" parameterType="" resultType="">
...
</select>
一、传递单参数(简单数据类型)
parameterType:
java.lang.String 改为 string / String / parameterType 不写,均可以【原因:Mybatis默认设置了别名】
使用简单类型为参数:在 #{ } 中的标识符可以随便写,但还是要有意义【{ } 中为形参】
1、使用简单数据类型(8基本数据类型+String),String
Jsr j = jsrDao.select1("A003");
System.out.println(j);
Jsr select1(String a003); //接口
<select id="select1" parameterType="string" resultType="Jsr">
select * from tb_jsr where id = #{id}
</select>
2、使用简单数据类型(8基本数据类型+String),int
List<Jsr> jList = jsrDao.select2(25);
for(Jsr j:jList) {
System.out.println(j);
}
List<Jsr> select2(int i); //接口
<select id="select2" parameterType="int" resultType="Jsr">
select * from tb_jsr where age = #{age}
</select>
二、传递多参数
/* 绝对不可以同时为SQL语句传递多个参数, 【测试 3 失败】 */
// 3、测试:parameterType 【需求:姓名为kpo,年龄为25】
// List<Jsr> jList = jsrDao.select3("kpo",25);
//List<Jsr> select3(String kpo, int i); //错误接口
<!--<select id="select3" parameterType="String int" resultType="Jsr">
select * from tb_jsr where name = #{name} and age = #{age}
</select>-->
为SQL语句传递多个参数 【需求:姓名为kpo,年龄为25】
4、使用domain(POJO / Java Bean)为参数
jj 参数为一个 domain 引用类型,那么 #{ } 中的标识符必须是 domain 类的属性名
Jsr jj = new Jsr();
jj.setName("kpo");
jj.setAge(25);
List<Jsr> jList = jsrDao.select4(jj);
for(Jsr j:jList) {
System.out.println(j);
}
List<Jsr> select4(Jsr jj); //接口
<select id="select4" parameterType="Jsr" resultType="Jsr">
select * from tb_jsr where name = #{name} and age = #{age}
</select>
5、使用 map 为参数
参数类型为 map 类型,那么 #{ } 中的标识符必须是 map 的 key
Map<String,Object> map = new HashMap<String, Object>();
map.put("name","kpo");
map.put("age",25);
List<Jsr> jList = jsrDao.select5(map);
for(Jsr j:jList) {
System.out.println(j);
}
List<Jsr> select5(Map<String, Object> map); //接口
<select id="select5" parameterType="map" resultType="Jsr">
select * from tb_jsr where name = #{name} and age = #{age}
</select>
10、使用 注解方式 传递多个参数
List<Jsr> jList = jsrDao.select10("kpo",25);
for(Jsr j:jList) {
System.out.println(j);
}
List<Jsr> select10(@Param("name") String kpo, @Param("age") int i);
<select id="select10" resultType="Jsr">
select * from tb_jsr where name = #{name} and age = #{age}
</select>
12、使用 混合模式 传递多个参数
Jsr jj = new Jsr();
jj.setName("kpo");
jj.setAge(25);
pageParams p = new pageParams();
p.setLimit(1);
p.setStart(0);
List<Jsr> jList = jsrDao.select12(jj,p);
for(Jsr j:jList) {
System.out.println(j);
}
List<Jsr> select12(@Param("params") Jsr jj, @Param("page") pageParams p);
<select id="select12" resultType="Jsr">
select * from tb_jsr where name = #{params.name} and age = #{params.age} limit #{page.start}, #{page.limit}
</select>
总结:
在实际开发项目中,使用 domain 引用类型(Java Bean),map集合类型,注解,混合模式都可以为SQL语句同时传递多个参数
- 一般情况(参数个数 > 5个),使用domain就可以;
- (参数个数 < 5个),使用注解方式;
- map尽量不使用,因为业务可读性丧失,后期扩展和维护性差;
- 使用混合模式时,要明确参数的合理性。
例子:(domain使用不了)需求:查询姓名为kpo,班级为一年一班学员详细情况。 [原因:s表没有id,c表没有classroom]
select * from tb_student s join tb_classroom c on s.classroom = c.id where s.name = #{name} and c.name = #{name}
三、模糊查询和#{ }与${ }区别
6、SQL语句使用 ${ } 拼接
Jsr j = jsrDao.select6("A004");
System.out.println(j);
Jsr select6(String a004);
<select id="select6" resultType="Jsr">
select * from tb_jsr where id = '${value}'
</select>
7、like模糊查询,使用 ${ }
List<Jsr> jList = jsrDao.select7("i");
for(Jsr j:jList) {
System.out.println(j);
}
List<Jsr> select7(String i);
<select id="select7" resultType="Jsr">
select * from tb_jsr where name like '%${value}%'
</select>
8、like模糊查询,使用 #{ } 占位,【"%i%"】
List<Jsr> jList = jsrDao.select8("%i%");
for(Jsr j:jList) {
System.out.println(j);
}
List<Jsr> select8(String i);
<select id="select8" resultType="Jsr">
select * from tb_jsr where name like #{name}
</select>
9、like模糊查询,使用 #{ } 占位,【like ‘%’ #{name} ‘%’】
List<Jsr> jList = jsrDao.select9("i");
for(Jsr j:jList) {
System.out.println(j);
}
List<Jsr> select9(String i);
<select id="select9" resultType="Jsr">
<!-- 注意'%' #{name} '%'中的空格 -->
select * from tb_jsr where name like '%' #{name} '%'
</select>
总结:
必须使用 ${ } 的情况
- i:需要动态拼接表名 select * from ${table_name}
- ii:动态拼接排序字段 select * from table_name order by ${username}
返回值类型 resultType
<select id="select" parameterType="" resultType="">
...
</select>
一、返回简单数据类型
13、返回String类型 【需求:查询id为A004的姓名】
String name = jsrDao.select13("A004");
System.out.println(name);
String select13(String a004);
<select id="select13" resultType="String">
select name from tb_jsr where id = #{id}
</select>
14、返回String类型 【需求:查询所有人的姓名】
List<String> stringList = jsrDao.select14();
for(String name_1:stringList){
System.out.println(name_1);
}
List<String> select14();
<select id="select14" resultType="String">
select name from tb_jsr
</select>
15、返回int类型 【需求:查询一共有多少条记录】
int count = jsrDao.select15();
System.out.println(count);
int select15();
<select id="select15" resultType="int">
select count(*) from tb_jsr
</select>
二、返回domain引用类型 (POJO)
16、返回domain引用类型 Jsr
代码省略
解析返回值为domain(Jsr)的:
* 解析返回值为Jsr的:
* <select id="select" resultType="Jsr">
* select * from tb_jsr
* <select/>
*
* 以上返回的是List<Jsr>集合
* 当执行了Sql语句后,通过查询得到结果:id,name,tel,age...
*
* 具体工作:
* (1)根据返回值类型,自动创建该类型对象,由该对象将查询结果封装
* Jsr j1 = new Jsr();
* j1.setId("A001");
* j1.setName("lx");
* ...
*
* (2)当查询出第二条记录,继续做操作(1)
* Jsr j2 = new Jsr();
* j2.setId("A001");
* j2.setName("lx");
* ...
*
* ...
*
* (n)重复以上步骤,直至查询结束(多条记录封装成多个返回值类型的对象)
*
* 最后,MyBatis系统自动创建List集合保存这些对象
* List<Jsr> jList = new ArrayList<>();
* jList.add(j1);
* jList.add(j2);
* ...
* jList.add(jn);
*
三、返回Map类型
17、返回map类型
使用 domain 无法进行查询结果封装时,使用map返回结果
为什么无法封装?
原因:SQL查询的结果集中的某些属性在 domain 中不存在,例如根据 name 统计表的记录条数count就不在 domain 中
List<Map<String,Object>> mapList = jsrDao.select17();
for(Map<String,Object> map:mapList){
Set<String> set = map.keySet();
for (String key:set) {
System.out.println("key:"+key);
System.out.println("value:"+map.get(key));
}
System.out.println("----------------------");
}
List<Map<String, Object>> select17();
<select id="select17" resultType="map">
select * from tb_jsr
</select>
解析返回值为map的:
* 解析返回值为map的:
* <select id="select" resultType="map">
* select * from tb_jsr
* <select/>
* 以上返回的是List<Map<String,Object>>集合
* 当执行了Sql语句后,通过查询得到结果:id,name,tel,age...
*
* 具体工作:
* (1)根据返回值类型,自动创建该类型对象,由该对象将查询结果保存起来
* Map<String,Object> map1 = new HashMap<>();
* map1.put("id","A001");
* ...
*
* (2)当查询出第二条记录,继续做操作(1)
* Map<String,Object> map2 = new HashMap<>();
* map2.put("id","A002");
* ...
*
* ...
*
* (n)重复以上步骤,直至查询结束(多条记录封装成多个map对象)
*
* 最后,MyBatis系统自动创建List集合保存这些map对象
* List<Map<String,Object>> mapList = new ArrayList();
* mapList.add(map1);
* ...
* mapList.add(mapn);
四、当查询的字段名与POJO(domain)属性名不一致时解决方法
【方式一:给字段起别名】
List<Jsr> jList = jsrDao.select18();
for(Jsr j:jList){
System.out.println(j);
}
List<Jsr> select18();
<select id="select18" resultType="Jsr">
select id,fullname as name,sex,age,tel,num,classroom from tb_jsr
</select>
【方式二:resultMap】
resultMap 作用:定义映射规则(SQL 到 Java Bean)
List<Jsr> jList = jsrDao.select19();
for(Jsr j:jList){
System.out.println(j);
}
List<Jsr> select19();
<!--
id:resultMap标签对的唯一标识
type:指定一个类型,与数据库表一一对应,建立起表字段和类属性的名字一一匹配的关系(可以是POJO全路径)
-->
<resultMap id="jsMap" type="Jsr">
<!--
id标签:用来配置主键的对应关系
result标签:用来配置普通字段的对应关系
property属性:配置的是类中的属性名
column属性:配置的是表中的字段名
-->
<id property="id" column="id"/>
<result property="name" column="fullname"/>
<result property="sex" column="sex"/>
<result property="age" column="age"/>
<result property="tel" column="tel"/>
<result property="num" column="num"/>
<result property="classroom" column="classroom"/>
</resultMap>
<select id="select19" resultMap="jsMap">
<!--
“ * ”代表:id,fullname,sex,...
过程:fullname ===> column的fullname,然后返回给property的name里
-->
select * from tb_jsr
</select>
分页参数 RowBounds
RowBounds 分页适用于小数据量查询。在映射文件中不需要配置 RowBounds 参数,MyBatis 自动识别。
原理:执行 SQL 查询后,按照偏移量(offset)和 限制条数(limit)返回查询结果。
RowBounds rowBounds = new RowBounds(0,20);
List<Jsr> jList = jsrDao.select26("kpo",20,rowBounds);
System.out.println(jList.size());
List<Jsr> select26(@Param("name") String name, @Param("age") int age,RowBounds rowBounds);
<select id="select26" resultType="Jsr">
select * from tb_jsr where name = #{name} and age = #{age}
</select>
动态SQL+SQL片段
一、动态SQL
27、if 标签 【根据tel查数据】
适用于选填条件的查询,参数不为空时,根据条件查询,为空时,全查询。
test 属性:判断的条件
List<Jsr> jList = jsrDao.select27("6");
for(Jsr j:jList) {
System.out.println(j);
}
List<Jsr> select27(String s);
<select id="select27" parameterType="String" resultType="Jsr">
select * from tb_jsr where 1=1
<!--适用于选填条件的查询,参数不为空时,进行模糊查询-->
<if test="tel != null and tel != ''">
and tel like concat('%',#{tel},'%')
</if>
</select>
20、where 标签 + if 标签
对 If 标签的改进(即:没有 1=1)
Jsr jj = new Jsr();
jj.setName("i");
//jj.setTel("1");
jj.setAge(25);
List<Jsr> jList = jsrDao.select20(jj);
for(Jsr j:jList){
System.out.println(j);
}
List<Jsr> select20(Jsr jj);
<select id="select20" resultType="Jsr">
select * from tb_jsr
<!--
where标签:
使用where标签时必须搭配where标签对中的if标签来使用
where标签会自动屏蔽第一个连接符 and/or
-->
<where>
<if test="name!=null and name!=''">
and name like '%' #{name} '%'
</if>
<if test="tel!=null and tel!=''">
and tel like '%' #{tel} '%'
</if>
<if test="age!=null">
and age = #{age}
</if>
</where>
</select>
28、choose + when + otherwise 标签
相当于 switch…case…default…
List<Jsr> jList = jsrDao.select28(null,null,"56");
for(Jsr j:jList){
System.out.println(j);
}
List<Jsr> select28(@Param("name") String lx,@Param("age") Integer i,@Param("tel") String s);
<select id="select28" resultType="Jsr">
select * from tb_jsr
<where>
<choose>
<when test="name != null and name != ''">
and name like concat('%',#{name},'%')
</when>
<when test="age != null and age != ''">
and age = #{age}
</when>
<otherwise>
and tel like concat('%',#{tel},'%')
</otherwise>
</choose>
</where>
</select>
29、set 标签
逗号必须添加,最后一个逗号会默认删除
Jsr jsr = new Jsr();
jsr.setId("A003");
jsr.setAge(26);
jsr.setTel("169******");
int num = jsrDao.update29(jsr);
if (num > 0) {
SqlSessionUtil.mybCommit(SqlSessionUtil.getSession());
}else {
SqlSessionUtil.getSession().rollback();
}
int update29(Jsr jsr);
<update id="update29" parameterType="jsr">
update tb_jsr
<set>
<!--逗号必须添加,最后一个逗号会默认删除-->
id = #{id},
<if test="age != null and age != ''">
age = #{age},
</if>
<if test="tel != null and tel != ''">
tel = #{tel},
</if>
</set>
where id = #{id}
</update>
30、trim 标签
prefix:前缀,表示向前添加内容 ;prefixOverrides:从前面删除内容
suffix:后缀,表示向后添加内容 ;suffixOverrides:从后面删除内容
Jsr jsr = new Jsr();
jsr.setId("A003");
jsr.setAge(26);
jsr.setTel("132******");
int num = jsrDao.update30(jsr);
if (num > 0) {
SqlSessionUtil.mybCommit(SqlSessionUtil.getSession());
}else {
SqlSessionUtil.getSession().rollback();
}
int update30(Jsr jsr);
<update id="update30" parameterType="jsr">
update tb_jsr
<trim prefix="set" prefixOverrides="," suffix="where" suffixOverrides="abc">
,id = #{id},age = #{age},tel = #{tel}abc
</trim>
id = #{id}
</update>
21、foreach 标签
用来遍历传递来的数组参数
collection属性:标识传递参数的类型 【array:数组,list:集合】
item属性:每一次遍历出来的元素,在使用该元素时,需要套用在 #{ } 中
index属性:当前元素在集合的位置下标
open属性:拼接循环的开始符号
close属性:拼接循环的结束符号
separator属性:元素与元素之间的分隔符
String str[] = {"A001","A002","A004"};
List<Jsr> jList = jsrDao.select21(str);
for(Jsr j:jList){
System.out.println(j);
}
List<Jsr> select21(String[] str);
<select id="select21" resultType="Jsr">
select * from tb_jsr where id in
<foreach collection="array" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
31、bind 标签
List<Jsr> jList = jsrDao.select31("6");
for(Jsr j:jList){
System.out.println(j);
}
List<Jsr> select31(String s);
<select id="select31" resultType="jsr">
select * from tb_jsr
<where>
<if test="tel != null and tel != ''">
<bind name="tel" value="'%'+ tel +'%'"/>
and tel like #{tel}
</if>
</where>
</select>
二、SQL片段
22、SQL片段 【根据id查单条】
Jsr jj = jsrDao.select22("A003");
System.out.println(jj);
Jsr select22(String a003);
<!--
在实际项目开发中,使用SQL片段来代替重复率高,且复杂的子查询
-->
<sql id="sq22">
select * from tb_jsr
</sql>
<select id="select22" resultType="Jsr">
<include refid="sq22"/> where id=#{id};
</select>
级联 + 缓存 + 存储过程