一.封装工具类
package com.neudeu.util;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
// 定义mybaties的配置文件路径
String resource = "SqlMapConfig.xml";
// 得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建会话工厂,传入mybaties的配置文件流
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static SqlSession getSession() {
return sqlSessionFactory.openSession();
}
}
二.数据库操作
1.插入记录,并获取主键
sql增删改都会返回int值,表示影响的行数,但insert标签中不能写resultType属性,所以想要获得插入记录的主键值需要经过一定处理;
常见于 插入于A表的该行记录主键 要作为 B表要插入记录的外键 时应用;
1.1使用selectKey标签
- keyProperty属性:就是主键名,对应java属性名;
- resultType属性:指的是主键的数据类型;
- order属性:执行的顺序 对应after和before两个值
before:先获取主键,在insert之前;
after:先insert,再获取主键;
DeptMapper.xml
<mapper namespace="com.neuedu.mapper.DeptMapper">
<!-- 插入部门信息 -->
<insert id="insertDept" parameterType="Dept" >
<!-- 获取主键 方式一:使用selectKey标签-->
<selectKey keyProperty="deptno" resultType="int" order="AFTER">
select LAST_INSERT_ID()
</selectKey>
insert into dept(dname,loc) values(#{dname},#{loc})
</insert>
</mapper>
1.2 使用useGeneratedKeys属性
- useGeneratedKeys设置为true ,自动获取数据库中的主键;
- keyProperty属性值设置为主键名;
- 只适用与有自增长的数据库(mysql,SqlServer);
DeptMapper.xml
<mapper namespace="com.neuedu.mapper.DeptMapper">
<!-- 插入部门信息 -->
<insert id="insertDept" parameterType="Dept" useGeneratedKeys="true" keyProperty="deptno" >
insert into dept(dname,loc) values(#{dname},#{loc})
</insert>
</mapper>
mybatis会使用JDBC的getGeneratedkeys方法获取由数据库内部自动生成的主键,
并将该值赋值给由keyProperty指定的属性
接口:DeptMapper.java
public interface DeptMapper {
//插入部门信息,返回值类型设置为主键数据类型
int insertDept(Dept dept);
}
测试类Test02.java
public class Test02 {
/**
* 向dept表中插入一条部门信息,并获取到这条信息的主键值
* insert into dept(dname,loc) values(#{dname},#{loc})
*/
@Test
public void insertDeptRecord() {
// 创建sqlsession
SqlSession sqlSession = MybatisUtils.getSession();
// 获取mapper代理对象,加载字节码文件
DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
// 通过代理对象调用方法
Dept dept = new Dept();
dept.setDname("安保部");
dept.setLoc("大连");
//返回的是影响行数
//int row = mapper.insertDept(dept);
mapper.insertDept(dept);
//提交事务
sqlSession.commit();
//释放资源
sqlSession.close();
System.out.println(dept.getDeptno());
}
2.多条件查询
- 将参数类型parameterType设置为对象类型,通过对象属性传入多个条件;
例子:根据部门名称和部门编号查找部门信息;要求名字中包含‘勤’字,且编号大于10。
DeptMapper.xml
<mapper namespace="com.neudeu.mapper.DeptMapper">
<select id="findDeptByNameAndDeptno" parameterType="dept" resultType="dept">
<!-- 转义字符 > 大于号-->
select * from dept where dname like '%${dname}%' and deptno > #{deptno}
</select>
接口:DeptMapper.java
public interface DeptMapper {
// 根据部门名称和编号查询部门信息
List<Dept> findDeptByNameAndDeptno(Dept dept);
}
测试类Test01_Dept.java
@Test
public void findDeptTest() {
// 创建sqlSession
SqlSession sqlSession = MybatisUtils.getSession();
// 获取代理对象
DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
// 创建对象
Dept dept = new Dept();
dept.setDeptno(10);
dept.setDname("勤");
// 通过mapper对象调用方法
List<Dept> list = mapper.findDeptByNameAndDeptno(dept);
for (Dept d : list) {
System.out.println(d.getDeptno());
System.out.println(d.getDname());
}
//关闭资源
sqlSession.close();
}
三.动态sql
主要用于解决查询条件不确定的情况。
1.if+where标签
- 通过where标签添加where
- 不需要考虑where后是否加and,mybatis会自动处理
- 不需要考虑是否加空格,mybatis会自动处理
- 没有 else 标签,也没有 else if 标签。
- 注意: job!=’’ 此处只可以判断是否为空,不能判断是否为某个值。也就是说:job!=‘经理’ 是不好使的
DeptMapper.xml
<mapper namespace="com.neudeu.mapper.DeptMapper">
<select id="findDeptByIfWhere" parameterType="dept" resultType="dept">
select * from dept
<where>
<if test="dname != null and dname != ''">
and dname like '%${dname}%'
</if>
<if test="deptno != null and deptno !=''">
and deptno > #{deptno}
</if>
</where>
</select>
</mapper>
接口:DeptMapper.java
public interface DeptMapper {
// 根据部门名称和编号查询部门信息(动态sql-ifwhere)
List<Dept> findDeptByIfWhere(Dept dept);
}
测试类Test01_Dept.java
@Test
public void findDeptByIfWhere() {
// 创建sqlSession
SqlSession sqlSession = MybatisUtils.getSession();
// 获取代理对象
DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
// 创建对象
Dept dept = new Dept();
dept.setDeptno(100);
// dept.setDname("勤");
// 通过mapper对象调用方法
List<Dept> list = mapper.findDeptByIfWhere(dept);
for (Dept d : list) {
System.out.println(d.getDeptno());
System.out.println(d.getDname());
}
sqlSession.close();
}
2.choose标签
- 自上而下执行when标签;
- 当某一个条件满足时,执行该标签内容,下面when标签中的内容则不再执行;
- 当所有when标签中的条件都不满足时,执行otherwise标签中内容;
(otherwise标签也可以不写)
DeptMapper.xml
<mapper namespace="com.neudeu.mapper.DeptMapper">
<select id="findDeptByChoose" parameterType="dept" resultType="dept">
select * from dept
<where>
<choose>
<!-- 多个when标签只能执行一个。上面的条件如果满足,以下则不再执行 -->
<when test="dname != null and dname != ''">
and dname like '%${dname}%'
</when>
<when test="deptno != null and deptno !=''">
and deptno > #{deptno}
</when>
<otherwise>
<!-- 当上面条件全部不满足时会执行 -->
</otherwise>
</choose>
</where>
</select>
</mapper>
接口:DeptMapper.java
public interface DeptMapper {
// 根据部门名称和编号查询部门信息(动态sql-choose)
List<Dept> findDeptByChoose(Dept dept);
}
测试类Test01_Dept.java
@Test
public void findDeptByChoose() {
// 创建sqlSession
SqlSession sqlSession = MybatisUtils.getSession();
// 获取代理对象
DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
// 创建对象
Dept dept = new Dept();
dept.setDeptno(100);
dept.setDname("勤");
// 通过mapper对象调用方法
List<Dept> list = mapper.findDeptByChoose(dept);
for (Dept d : list) {
System.out.println(d.getDeptno());
System.out.println(d.getDname());
}
sqlSession.close();
}
3.foreach标签
- 用于遍历参数中的数组或集合;
- collection属性:需要遍历的类型值有:list array;
(当传入多个参数时,collection属性值为形参名。 —2022/01/06) - item属性:表示遍历出来的元素;
- open属性:表示起始位置所拼接的内容;
- close属性:表示结束位置所拼接的内容;
- separato属性:每次迭代之间的符号;
- index属性:每次迭代的位置索引,就是循环变量
3.1遍历数组
DeptMapper.xml
<mapper namespace="com.neudeu.mapper.DeptMapper">
<select id="findDeptByIds" parameterType="int" resultType="dept">
select * from dept where deptno in
<foreach collection="array" item="deptno" open="(" close=")" separator=",">
#{deptno}
</foreach>
</select>
</mapper>
接口:DeptMapper.java
public interface DeptMapper {
//查询部门编号是10,20,30的部门信息(foreach标签)
List<Dept> findDeptByIds(int[] arr);
}
测试类Test01_Dept.java
@Test
public void findDeptByIds() {
// 创建sqlSession
SqlSession sqlSession = MybatisUtils.getSession();
// 获取代理对象
DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
//定义数组
int[] arr = {10,20,30};
// 使用mapper对象调用方法
List<Dept> list = mapper.findDeptByIds(arr);
for(Dept dept:list) {
System.out.println(dept);
}
sqlSession.close();
}
3.2遍历集合
DeptMapper.xml
<mapper namespace="com.neudeu.mapper.DeptMapper">
<select id="findDeptByIdsList" parameterType="java.lang.Integer" resultType="dept">
select * from dept where deptno in
<foreach collection="list" item="deptno" open="(" close=")" separator=",">
#{deptno}
</foreach>
</select>
</mapper>
接口:DeptMapper.java
public interface DeptMapper {
//查询部门编号是10,20,30的部门信息(foreach标签)
List<Dept> findDeptByIdsList(List<Integer> list);
}
测试类Test01_Dept.java
@Test
public void findDeptByIdsList() {
// 创建sqlSession
SqlSession sqlSession = MybatisUtils.getSession();
// 获取代理对象
DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
//定义集合
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(10);
arrayList.add(20);
arrayList.add(30);
// 使用mapper对象调用方法
List<Dept> list = mapper.findDeptByIdsList(arrayList);
for(Dept dept:list) {
System.out.println(dept);
}
sqlSession.close();
}
四.resultMap
当sql语句中的字段名与实体对象中的属性名不一致时使用。
- type属性:表示映射的实体对象
- id属性:resultMap的唯一标识
- 子标签id:用于配置主键的映射
- property属性:实体类中属性名
- column属性:属性对应的字段名
- 子标签result:用于配置普通字段的映射
- property属性:实体类中属性名
- column属性:属性对应的字段名
- 子标签association :配置单个对象的关联映射(对象中的对象)
- property属性:该对象中的属性名
- javaType属性:该对象类型
javabean Emp.java
package com.neudeu.pojo;
import java.util.Date;
/*
* emp-->dept 多对一关系
* 在多的一方 设置 一的对象
*/
public class Emp {//
private int empno;
...
private Dept dept; //Dept对象属性
public int getEmpno() {
return empno;
}
public void setEmpno(int empno) {
this.empno = empno;
}
...
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Emp [empno=" + empno + ", ename=" + ename + ", job=" + job + ", mgr=" + mgr + ", hiredate=" + hiredate
+ ", sal=" + sal + ", comm=" + comm + ", deptno=" + deptno + ", dept=" + dept + "]";
}
}
EmpMapper.xml
<mapper namespace="com.neudeu.mapper.EmpMapper">
<!-- 定义方法 根据员工编号查询员工信息以及员工所在部门信息 -->
<!-- 定义resultMap -->
<resultMap type="emp" id="empResultMap">
<!-- 主键映射 -->
<id property="empno" column="empno"/>
<!-- 普通映射 -->
<result property="ename" column="ename"/>
<result property="job" column="job"/>
...
<!-- 配置单个对象的关联映射 -->
<!-- property是属性名 javaType是对象类型-->
<association property="dept" javaType="dept">
<!-- 主键映射 -->
<id property="deptno" column="dno"/><!-- dno 与dept.deptno别名 dno 相同-->
<!-- 普通字段 -->
<result property="dname" column="dn"/><!-- dn 与dept.dname别名 dn相同-->
<result property="loc" column="dl"/><!-- dl 与dept.loc别名 dl相同-->
</association>
</resultMap>
<!-- 将定义好的resultMap的唯一标识id 赋值为resultMap属性-->
<select id="selectEmpAndDeptById" parameterType="int" resultMap="empResultMap">
SELECT
emp.*,
dept.deptno AS 'dno',
dept.dname AS 'dn',
dept.loc AS 'dl'
FROM
emp
LEFT JOIN dept ON emp.deptno = dept.deptno
WHERE emp.empno = #{empno}
</select>
</mapper>
接口:EmpMapper.java
public interface EmpMapper {
//定义方法--根据员工编号查询员工信息以及员工所在部门信息
Emp selectEmpAndDeptById(int empno);
}
测试类Test02_Emp.java
@Test
public void findEmpAndDeptTest() {
// 创建sqlSession
SqlSession sqlSession = MybatisUtils.getSession();
// 获取代理对象
EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
//访问方法
Emp emp = mapper.selectEmpAndDeptById(7788);
System.out.println(emp);
int d = emp.getDept().getDeptno();
System.out.println(d);
sqlSession.close();
}
五.输入/输出类型总结
1.输入映射类型(parameterType)
- 当sql语句需要一个参数时
1.接口方法参数为一个基本数据类型:parameterType配置一个基本数据类型; - 当sql语句需要多个参数时
1.接口方法参数为一个实体对象类型:parameterType配置一个实体对象类型;
2.接口方法参数为一个集合类型(List,Map):parameterType配置集合中元素的类型;
2.输出映射类型(resultType)
- 当sql语句中的字段名与实体对象中的属性名一致时,使用resultType:
1.返回一条记录时,resultType可以配置成对象类型
2.返回多条记录时,resultType也要配置成对象类型(表示集合中存储的对象)
3.返回一条记录,且只有一列时,resultType可以配置成简单数据类型。 - 当sql语句中的字段名与实体对象中的属性名不一致时,使用resultMap:
1.在resultMap中,显式的书写sql字段名与实体对象属性名的映射