MyBatis+PostgreSQL+IDEA学习笔记(三)
三、MyBatis映射文件
1. 数据库的增删改查
(1)在Java Bean文件中添加构造器
Employee.java
public Employee() {
super();
}
public Employee(String id, String lastName, String gender, String email) {
this.id = id;
this.lastName = lastName;
this.gender = gender;
this.email = email;
}
(2)在DAO.Mapper文件中添加方法
(DAO = Data Access Object 这个包用于存放数据库操作相关的类)
EmployeeMapper.java
package mybatis.dao;
import mybatis.bean.Employee;
public interface EmployeeMapper {
//查
public Employee getEmpById(String id);
//增
public void addEmp(Employee employee);
//改
public void updateEmp(Employee employee);
//删
public void deleteEmpById(String id);
}
(3)在Mapper XML配置文件中添加语句
EmployeeMapper.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">
<!--
namespace:名称空间;指定为接口的全类名
id:唯一标识
resultType:返回值类型
parameterType:传入参数类型(可以不写)
#{id}:从传递过来的参数中取出id值
${}: $表示取值 {}大括号表示变量 取整型类型变量
#{}: #表示取值 {}大括号表示变量 取字符类型变量
-->
<mapper namespace="mybatis.dao.EmployeeMapper">
<select id="getEmpById" resultType="mybatis.bean.Employee">
select * from tb1_employee where id = #{id}
</select>
<insert id="addEmp" parameterType="mybatis.bean.Employee">
insert into tb1_employee(id,last_name,gender,email)
values(#{id},#{lastName},#{gender},#{email})
</insert>
<update id="updateEmp">
update tb1_employee
set last_name=#{lastName},gender=#{gender},email=#{email}
where id=#{id}
</update>
<delete id="deleteEmpById">
delete from tb1_employee where id=#{id}
</delete>
</mapper>
(4)测试函数
MyBatisTest.java
/*
* 测试增删改查
*1、mybatis允许增删改直接定义以下类型返回值
* Integer、Long、Boolean、void
*2、我们需要手动提交数据
* sqlSessionFactory.openSession();===》手动提交
* sqlSessionFactory.openSession(true);===》自动提交
* */
@Test
public void test03() throws IOException {
SqlSessionFactory sqlSessionFactory =getSqlSessionFactory();
//获取的SqlSession对象不会自动提交数据
SqlSession openSession=sqlSessionFactory.openSession();
try {
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
//测试添加
Employee employee1 = new Employee("002", "Jerry", "0", "654321@gmil.com");
mapper.addEmp(employee1);
//测试修改
Employee employee2 = new Employee("002", "Mark", "1", "12345678@gmil.com");
mapper.updateEmp(employee2);
//测试删除
mapper.deleteEmpById("002");
//测试查询
Employee employee3 = mapper.getEmpById("001");
System.out.println(employee3);
//手动提交
openSession.commit();
}finally {
openSession.close();
}
}
(5)测试结果
1)IDEA中
增
改
删
查
2)终端中查询结果
2. MyBatis参数处理
(1)单个参数
单个参数:mybatis不会做特殊处理,
#{参数名/任意名}:取出参数值。
(2)多个参数
1)原始方法
多个参数:mybatis会做特殊处理。
多个参数会被封装成 一个map,
key:param1...paramN,或者参数的索引也可以
value:传入的参数值
#{}就是从map中获取指定的key的值;
例:
EmployeeMapper.java
package mybatis.dao;
import mybatis.bean.Employee;
public interface EmployeeMapper {
//传入多个参数
public Employee getEmpByIdAndLastName(String id,String lastName);
}
EmployeeMapper.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="mybatis.dao.EmployeeMapper">
<select id="getEmpByIdAndLastName" resultType="mybatis.bean.Employee">
select * from tb1_employee where id = #{param1} and last_name = #{param2}
</select>
</mapper>
MyBatisTest.java
package mybatis.test;
import mybatis.bean.Employee;
import mybatis.dao.EmployeeMapper;
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;
import org.junit.Test;
public class MyBatisTest {
public SqlSessionFactory getSqlSessionFactory() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
return new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void test04() throws IOException {
SqlSessionFactory sqlSessionFactory =getSqlSessionFactory();
//获取的SqlSession对象不会自动提交数据
SqlSession openSession=sqlSessionFactory.openSession();
try {
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
//传入多个参数
Employee employee = mapper.getEmpByIdAndLastName("002","Tom");
System.out.println(employee);
//手动提交
openSession.commit();
}finally {
openSession.close();
}
}
}
结果
2)命名参数
1⃣️原始方法
命名参数:明确指定封装参数时map的key;@Param(“id”)
多个参数会被封装成 一个map,
key:使用@Param注解指定的值
value:参数值
#{指定的key}取出对应的参数值
例:
EmployeeMapper.java
package mybatis.dao;
import mybatis.bean.Employee;
import org.apache.ibatis.annotations.Param;
public interface EmployeeMapper {
//传入多个参数 命名参数
public Employee getEmpByIdAndLastName(@Param("id")String id, @Param("lastName")String lastName);
}
EmployeeMapper.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="mybatis.dao.EmployeeMapper">
<select id="getEmpByIdAndLastName" resultType="mybatis.bean.Employee">
select * from tb1_employee where id = #{id} and last_name = #{lastName}
</select>
</mapper>
MyBatisTest.java 测试函数 Test04( ) 同上
结果
2⃣️其他命名方法
POJO:
如果多个参数正好是我们业务逻辑的数据模型,我们就可以直接传入pojo;
#{属性名}:取出传入的pojo的属性值
Map:
如果多个参数不是业务模型中的数据,没有对应的pojo,不经常使用,为了方便,我们也可以传入map
#{key}:取出map中对应的值
TO:
如果多个参数不是业务模型中的数据,但是经常要使用,推荐来编写一个TO(Transfer Object)数据传输对象
例如:
Page{
int index;
int size;
}
3⃣️具体场景
1. 一个参数命名,另一个不命名
public Employee getEmp(@Param("id")Integer id,String lastName);
取值:id==>#{id/param1} lastName==>#{param2}
2. 传入一个值和一个对象
public Employee getEmp(Integer id,@Param("e")Employee emp);
取值:id==>#{param1} lastName===>#{param2.lastName/e.lastName}
3. 传入Collection(List、Set)类型或者是数组
如果是Collection(List、Set)类型或者是数组,也会特殊处理。把传入的list或者数组封装在map中。
key:Collection(collection),List (list),数组(array)
public Employee getEmpById(List<Integer> ids);
取值:取出第一个id的值: #{list[0]}
(3)参数值的获取
#{}:可以获取map中的值或者pojo对象属性的值;
${}:可以获取map中的值或者pojo对象属性的值;
区别:
#{}:是以预编译的形式,将参数设置到sql语句中;PreparedStatement;防止sql注入
${}:取出的值直接拼装在sql语句中;会有安全问题;
大多情况下,我们取参数的值都应该去使用#{};
原生jdbc不支持占位符的地方,可以使用${}进行取值
例如分表、排序等:
select * from ${year}_salary where xxx;
select * from tbl_employee order by ${f_name} ${order}
#{}:更丰富的用法:
可以规定参数的一些规则:
javaType、 jdbcType、 mode(存储过程)、 numericScale、
resultMap、 typeHandler、 jdbcTypeName、 expression(未来准备支持的功能);
jdbcType通常需要在某种特定的条件下被设置:
在数据为null的时候,有些数据库可能不能识别mybatis对null的默认处理。比如Oracle、PostgreSQL,
报错:JdbcType OTHER:无效的类型
这是因为mybatis对所有的null都映射的是原生Jdbc的OTHER类型,oracle不能正确处理;
解决方案:
1、在映射文件中设置 #{id,jdbcType=NULL};
例:
<select id="getEmpById,jdbcType=NULL" resultType="mybatis.bean.Employee">
select * from tb1_employee where id = #{id}
</select>
2、在全剧配置文件中设置 jdbcTypeForNull=NULL
<settings>
<setting name="jdbcTypeForNull" value="NULL"/>
</settings>
3. MyBatis Select查询
(1)返回对象是列表或集合
EmployeeMapper.java
//返回对象列表
public List<Employee> getEmployeeByLastNameLike(String lastName);
EmployeeMapper.xml
注意:resultType:如果返回的是一个集合,要写集合中元素的类型
<!--返回对象列表-->
<select id="getEmployeeByLastNameLike" resultType="mybatis.bean.Employee">
select * from tb1_employee where last_name like #{lastName}
</select>
MyBatisTest.java
@Test
public void test04() throws IOException {
SqlSessionFactory sqlSessionFactory =getSqlSessionFactory();
//获取的SqlSession对象不会自动提交数据
SqlSession openSession=sqlSessionFactory.openSession();
try {
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
//查询 返回对象列表
List<Employee> like = mapper.getEmployeeByLastNameLike("%e%");
//打印
for(Employee employee : like){
System.out.println(employee);
}
//手动提交
openSession.commit();
} finally {
openSession.close();
}
}
测试结果
(2)返回对象是map
EmployeeMapper.java
//返回一条记录的map:key是列名,值是对应的返回值
public Map<String,Object> getEmpByIdReturnMap(String id);
//多条记录封装一个map:Map<String,Employee>:键是这条记录的主键,值是记录封装后的javaBean
//@MapKey:告诉mybatis封装这个map的时候使用哪个属性作为map的key
@MapKey("id")
public Map<String, Employee> getEmpByLastNameLikeReturnMap(String lastName);
EmployeeMapper.xml
<!--返回一条记录的map:key是列名,值是对应的返回值-->
<select id="getEmpByIdReturnMap" resultType="map">
select * from tb1_employee where id = #{id}
</select>
<!--多条记录封装一个map-->
<!--resultType:想要封装的对象的类型-->
<select id="getEmpByLastNameLikeReturnMap" resultType="mybatis.bean.Employee">
select * from tb1_employee where last_name like #{lastName}
</select>
MyBatisTest.java
@Test
public void test04() throws IOException {
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
//获取的SqlSession对象不会自动提交数据
SqlSession openSession=sqlSessionFactory.openSession();
try {
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
//查询 返回单条记录map
Map<String, Object> map = mapper.getEmpByIdReturnMap("001");
System.out.println(map);
//查询 返回多条记录封装一个map
Map<String, Employee> map = mapper.getEmpByLastNameLikeReturnMap("%y%");
System.out.println(map);
//手动提交
openSession.commit();
} finally {
openSession.close();
}
}
测试结果:
- map是单条对象
- map是多条对象
4. ResultMap标签
resultMap可以实现将查询结果映射为复杂类型的pojo,可以通过ResultMap实现一对多的查询。
例1:指定封装规则
<!--自定义某个javaBean的封装规则
type:自定义规则的Java类型
id:唯一id方便引用
-->
<resultMap id="MySimpleEmp" type="mybatis.bean.Employee">
<!--指定主键列的封装规则
id定义主键会底层有优化;
column:指定哪一列
property:指定对应的javaBean属性
-->
<id column="id" property="id"/>
<!-- 定义普通列封装规则 -->
<result column="last_name" property="lastName"/>
<!-- 其他不指定的列会自动封装:我们只要写resultMap就把全部的映射规则都写上。 -->
<result column="email" property="email"/>
<result column="gender" property="gender"/>
</resultMap>
<!-- resultMap:自定义结果集映射规则; -->
<select id="getEmpById" resultMap="MySimpleEmp">
select * from tb1_employee where id=#{id}
</select>
例2: 联合查询
<!--
联合查询:级联属性封装结果集
-->
<resultMap type="mybatis.bean.Employee" id="MyDifEmp">
<id column="id" property="id"/>
<result column="last_name" property="lastName"/>
<result column="gender" property="gender"/>
<result column="did" property="dept.id"/>
<result column="dept_name" property="dept.departmentName"/>
</resultMap>
<select id="getEmpAndDept" resultType="mybatis.bean.Employee">
select e.id id,e.last_name last_name,e.gender gender,e.d_id d_id,d.dept_name dept_name
from tb1_employee e,tb1_dept d
where d.id=e.d_id and e.id = '001';
</select>