- Sql 映射文件
- 1、增删改的实现
- 2、获取自增主键的值
- 3、参数处理
- 3.1、关于参数的扩展思考
- 3.2、结合源码,mybatis 怎么处理参数
- 3.3、参数值的获取:# 与 $ 的区别
- 4、Select 返回 List
- 5、Select 记录封装 Map
- 6、Select 中 resultMap 属性:自定义结果映射查询
MyBatis 的真正强大在于它的语句映射,这是它的魔力所在。由于它的异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 致力于减少使用成本,让用户能更专注于 SQL 代码。
1、增删改的实现首先我们在接口中定义方法:
import mybatis.Employee;
public interface EmployeeMapper {
public Employee getEmpById(Integer id);
public void addEmp(Employee employee);
public void updateEmp(Employee employee);
public void deleteEmpById(Integer id);
}
接着,在 Sql 映射文件中给出对应的 Sql 语句实现:
测试代码:
@Test
public void test4() throws IOException {
//1、获取sqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
//2、获取sqlSession对象,不会自动提交数据
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
//3、获取接口的实现类对象
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
mapper.addEmp(new Employee(null, "jerry", "jerry@qq.com", "1"));
//4、手动提交
sqlSession.commit();
}finally {
sqlSession.close();
}
}
@Test
public void test5() throws IOException {
//1、获取sqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
//2、获取sqlSession对象,不会自动提交数据
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
//3、获取接口的实现类对象
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
mapper.updateEmp(new Employee(1, "jerry01", "jerry01@qq.com", "0"));
//4、手动提交
sqlSession.commit();
}finally {
sqlSession.close();
}
}
@Test
public void test6() throws IOException {
//1、获取sqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
//2、获取sqlSession对象,不会自动提交数据
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
//3、获取接口的实现类对象
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
mapper.deleteEmpById(1);
//4、手动提交
sqlSession.commit();
}finally {
sqlSession.close();
}
}
注意:
mybatis允许增删改直接定义以下类型返回值:
Integer、Long、Boolean、void
必须手动提交数据。
sqlSessionFactory.openSession() ==> 手动提交
sqlSessionFactory.openSession(true) ==> 自动提交
2、获取自增主键的值
insert 标签里边的 useGeneratedKeys 属性和 keyProperty 属性。
insert into tbl_employee(last_name, email, gender) values(#{lastname}, #{email}, #{gender})
测试代码:
@Test
public void test4() throws IOException {
//1、获取sqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
//2、获取sqlSession对象,不会自动提交数据
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
//3、获取接口的实现类对象
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
Employee employee = new Employee(null, "jerry", "jerry@qq.com", "1");
//此时employee对象的id还为null
mapper.addEmp(employee);
System.out.println(employee.getId());//3,打印输出3
//4、手动提交
sqlSession.commit();
}finally {
sqlSession.close();
}
}
3、参数处理
-
异常:
org.apache.ibatis.binding.BindingException:
Parameter 'id' not found.
Available parameters are [1, 0, param1, param2] -
操作:
方法:public Employee getEmpByIdAndLastName(Integer id,String lastName);
取值:#{id},#{lastName}
-
单个参数:mybatis 不会做特殊处理
#{参数名/任意名}:取出参数值。
-
多个参数:mybatis 会做特殊处理
多个参数会被封装成一个 map:
key:param1…paramN,或者参数的索引也可以
value:传入的参数值
#{} 就是从 map 中获取指定的 key 的值;
定义一个多参数查询方法:
public interface EmployeeMapper {
public Employee getEmpByIdAndLastName(Integer id, String lastname);
public Employee getEmpById(Integer id);
public void addEmp(Employee employee);
public void updateEmp(Employee employee);
public void deleteEmpById(Integer id);
}
在 Sql 映射文件中写出 sql 语句:
测试代码:
@Test
public void test7() throws IOException {
//1、获取sqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
//2、获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
//3、获取接口的实现类对象
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
Employee jerry = mapper.getEmpByIdAndLastName(2, "jerry");
System.out.println(jerry);
}finally {
sqlSession.close();
}
}
DEBUG 12-22 20:12:43,544 ==> Preparing: select * from tbl_employee where id = ? and last_name = ? (baseJdbcLogger.java:137)
DEBUG 12-22 20:12:43,600 ==> Parameters: 2(Integer), jerry(String) (baseJdbcLogger.java:137)
DEBUG 12-22 20:12:43,630 <== Total: 1 (baseJdbcLogger.java:137)
Employee{id=2, lastname='jerry', email='jerry@qq.com', gender='1'}
-
【命名参数】:明确指定封装参数时 map 的 key;@Param("id")
多个参数会被封装成一个 map:
key:使用 @Param 注解指定的值
value:参数值
#{指定的key} 取出对应的参数值
修改接口:
public interface EmployeeMapper {
public Employee getEmpByIdAndLastName(@Param("id")Integer id, @Param("lastname")String lastname);
修改 Sql 映射文件:
select * from tbl_employee where id = #{id} and last_name = #{lastname}
-
POJO
如果多个参数正好是我们业务逻辑的数据模型,我们就可以直接传入 pojo;
#{属性名}:取出传入的 pojo 的属性值
-
Map
如果多个参数不是业务模型中的数据,没有对应的 pojo,不经常使用,为了方便,我们也可以传入 map
#{key}:取出 map 中对应的值
添加一个查询:
public interface EmployeeMapper {
public Employee getEmpByMap(Map map);
在 Sql 映射文件中也对应添加:
测试代码:
@Test
public void test8() throws IOException {
//1、获取sqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
//2、获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
//3、获取接口的实现类对象
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
HashMap map = new HashMap<>();
map.put("id", 2);
map.put("lastName", "jerry");
Employee employee = mapper.getEmpByMap(map);
System.out.println(employee);
}finally {
sqlSession.close();
}
}
3.1、关于参数的扩展思考
-
public Employee getEmp(@Param("id")Integer id, String lastName);
取值:id ==> #{id/param1} lastName ==> #{param2}
-
public Employee getEmp(Integer id, @Param("e")Employee emp);
取值:id ==> #{param1} lastName ===> #{param2.lastName/e.lastName}
特别注意:如果是 Collection(List、Set) 类型或者是数组也会特殊处理。也是把传入的 list 或者数组封装在 map 中。
key:Collection(collection), 如果是 List 还可以使用这个 key(list)、数组(array)
-
public Employee getEmpById(List
ids); 取值:取出第一个 id 的值:#{list[0]}
总结:参数多时会封装 map,为了不混乱,我们可以使用 @Param 来指定封装时使用的 key;
#{key} 就可以取出 map 中的值;
-
(@Param("id")Integer id,@Param("lastName")String lastName);
ParamNameResolver 解析参数封装 map 的;
//1、names:{0=id, 1=lastName};构造器的时候就确定好了
确定流程:
-
获取每个标了 param 注解的参数的 @Param 的值:id,lastName; 赋值给 name;
-
每次解析一个参数给 map 中保存信息:(key:参数索引,value:name 的值)
name 的值:
标注了 param 注解:注解的值
没有标注:
- 全局配置:useActualParamName(jdk1.8):name=参数名
- name=map.size();相当于当前元素的索引
{0=id, 1=lastName,2=2}
-
args【1,“Tom”, ‘hello’】:
public Object getNamedParams(Object[] args) {
final int paramCount = names.size();
//1、参数为null直接返回
if (args == null || paramCount == 0) {
return null;
//2、如果只有一个元素,并且没有Param注解;args[0]:单个参数直接返回
} else if (!hasParamAnnotation && paramCount == 1) {
return args[names.firstKey()];
//3、多个元素或者有Param标注
} else {
final Map param = new ParamMap
3.3、参数值的获取:# 与 $ 的区别
- #{}:可以获取 map 中的值或者 pojo 对象属性的值;
- ${}:可以获取 map 中的值或者 pojo 对象属性的值;
select * from tbl_employee where id=${id} and last_name=#{lastName}
查询结果:
DEBUG 12-24 10:11:13,514 ==> Preparing: select * from tbl_employee where id = 2 and last_name = ? (baseJdbcLogger.java:137) DEBUG 12-24 10:11:13,558 ==> Parameters: null (baseJdbcLogger.java:137) DEBUG 12-24 10:11:13,584 <== Total: 0 (baseJdbcLogger.java:137) null
区别:
- #{}:是以预编译的形式,将参数设置到 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(报错);
JdbcType OTHER:无效的类型;因为 mybatis 对所有的 null 都映射的是原生 Jdbc 的 OTHER 类型,oracle 不能正确处理;
由于全局配置中:jdbcTypeForNull=OTHER;oracle 不支持;两种办法:
-
#{email,jdbcType=OTHER};
-
jdbcTypeForNull=NULL
4、Select 返回 List
数据库中的数据:
mysql> select * from tbl_employee; +----+-----------+--------+---------------+ | id | last_name | gender | email | +----+-----------+--------+---------------+ | 1 | jerry2 | 0 | jerry3@qq.com | | 2 | jerry1 | 1 | jerry1@qq.com | | 3 | jerry | 1 | jerry@qq.com | +----+-----------+--------+---------------+ 3 rows in set (0.00 sec)
定义接口中的查询方法:
public interface EmployeeMapper {
public List getEmpsByLastNameLike(String lastname);
定义 sql 映射文件中的查询语句:
select * from tbl_employee where last_name like #{lastName}
测试代码:
@Test
public void test9() throws IOException {
//1、获取sqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
//2、获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
//3、获取接口的实现类对象
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
List empsByLastNameLike = mapper.getEmpsByLastNameLike("%e%");
for (Employee e :
empsByLastNameLike ) {
System.out.println(e);
}
}finally {
sqlSession.close();
}
}
DEBUG 12-24 10:38:41,001 ==> Preparing: select * from tbl_employee where last_name like ? (baseJdbcLogger.java:137)
DEBUG 12-24 10:38:41,035 ==> Parameters: %e%(String) (baseJdbcLogger.java:137)
DEBUG 12-24 10:38:41,150 <== Total: 3 (baseJdbcLogger.java:137)
Employee{id=1, lastname='jerry2', email='jerry3@qq.com', gender='0'}
Employee{id=2, lastname='jerry1', email='jerry1@qq.com', gender='1'}
Employee{id=3, lastname='jerry', email='jerry@qq.com', gender='1'}
如果返回的是一个集合,只需要写集合中元素的类型即可!
5、Select 记录封装 Map
定义接口中的查询方法:
public interface EmployeeMapper {
//返回一条记录的map:key就是列名,值就是对应的值
public Map getEmpByIdReturnMap(Integer id);
定义 sql 映射文件中的查询语句:
测试代码:
@Test
public void test10() throws IOException {
//1、获取sqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
//2、获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
//3、获取接口的实现类对象
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
Map empByIdReturnMap = mapper.getEmpByIdReturnMap(1);
System.out.println(empByIdReturnMap);
}finally {
sqlSession.close();
}
}
DEBUG 12-24 10:54:45,092 ==> Preparing: select * from tbl_employee where id = ? (baseJdbcLogger.java:137)
DEBUG 12-24 10:54:45,125 ==> Parameters: 1(Integer) (baseJdbcLogger.java:137)
DEBUG 12-24 10:54:45,149 <== Total: 1 (baseJdbcLogger.java:137)
{gender=0, last_name=jerry2, id=1, email=jerry3@qq.com} //HashMap 是无序的
如果想封装多条记录:
public interface EmployeeMapper {
//多条记录封装一个map:Map,键是这条记录的主键,值是记录封装后的javaBean
@MapKey("id") //告诉mybatis,封装这个map的时候使用哪个属性作为主键
public Map getEmpByLastNameLikeRetrunMap(String lastName);
select * from tbl_employee where last_name like #{lastName}
@Test
public void test11() throws IOException {
//1、获取sqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
//2、获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
//3、获取接口的实现类对象
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
Map empByLastNameLikeRetrunMap = mapper.getEmpByLastNameLikeRetrunMap("%r%");
System.out.println(empByLastNameLikeRetrunMap);
}finally {
sqlSession.close();
}
}
DEBUG 12-24 11:01:43,224 ==> Preparing: select * from tbl_employee where last_name like ? (baseJdbcLogger.java:137)
DEBUG 12-24 11:01:43,256 ==> Parameters: %r%(String) (baseJdbcLogger.java:137)
DEBUG 12-24 11:01:43,277 <== Total: 3 (baseJdbcLogger.java:137)
{1=Employee{id=1, lastname='jerry2', email='jerry3@qq.com', gender='0'}, 2=Employee{id=2, lastname='jerry1', email='jerry1@qq.com', gender='1'}, 3=Employee{id=3, lastname='jerry', email='jerry@qq.com', gender='1'}}
如果想把 lastName 作为 key:
@MapKey("lastname")
public Map getEmpByLastNameLikeRetrunMap(String lastName);
DEBUG 12-24 11:06:00,448 ==> Preparing: select * from tbl_employee where last_name like ? (baseJdbcLogger.java:137)
DEBUG 12-24 11:06:00,482 ==> Parameters: %r%(String) (baseJdbcLogger.java:137)
DEBUG 12-24 11:06:00,503 <== Total: 3 (baseJdbcLogger.java:137)
{jerry2=Employee{id=1, lastname='jerry2', email='jerry3@qq.com', gender='0'}, jerry1=Employee{id=2, lastname='jerry1', email='jerry1@qq.com', gender='1'}, jerry=Employee{id=3, lastname='jerry', email='jerry@qq.com', gender='1'}}
6、Select 中 resultMap 属性:自定义结果映射查询
新建一个接口 EmployeePlus:
public interface EmployeePlus {
public Employee getEmpById(Integer id);
}
新建一个 sql 映射文件 EmployeeMapperPlus:
测试代码:
public class MyBatisPlus {
public SqlSessionFactory getSqlSessionFactory() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
return new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void test1() throws IOException {
//1、获取sqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
//2、获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
//3、获取接口的实现类对象
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
Employee empById = mapper.getEmpById(1);
System.out.println(empById);
}finally {
sqlSession.close();
}
}
}
DEBUG 12-24 11:36:01,243 ==> Preparing: select * from tbl_employee where id = ? (baseJdbcLogger.java:137)
DEBUG 12-24 11:36:01,293 ==> Parameters: 1(Integer) (baseJdbcLogger.java:137)
DEBUG 12-24 11:36:01,328 <== Total: 1 (baseJdbcLogger.java:137)
Employee{id=1, lastname='jerry2', email='jerry3@qq.com', gender='0'}



