【MyBatis】MyBatis学习笔记二(DAO代理、输入、输出)
1、DAO代理
1.1 MyBatis 提供代理
- MyBatis创建Dao接口的实现类对象,完成对sql语句的执行。MyBatis创建一个对象代替dao实现类的功能。
1.2 使用MyBatis的要求
1)mapper文件中的namespace一定为dao接口的全限定名称。
2)mapper文件中SQL标签的id是dao接口的方法名。
3)mapper文件与dao接口必须在同一个目录下。
4)mapper文件与dao接口的文件名必须一致。
5)mapper文件中标签的parameterType属性值与dao接口中的方法参数类型完全一致。
6)在mybatis-config.xml文件中注册mapper文件时,使用 class=接口的完全限定名称。
1.3 MyBatis代理实现方式
-
使用SqlSession对象的方法 getMapper(dao.class)
-
例(StudentDao接口):
package com.Etui.dao; import com.Etui.entity.Student; public interface StudentDao { // 查询一条记录 Student selectStudentById(Integer id); }
mapper文件如下:
<?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.Etui.dao.StudentDao"> <!-- 根据id查询Student记录 --> <select id="selectStudentById" resultType="com.Etui.entity.Student"> select * from student where id = #{id} </select> </mapper>
-
通过MyBatis代理实现的查询功能:
import com.Etui.dao.StudentDao; import com.Etui.entity.Student; import com.Etui.uitls.MyBatisUtil; import org.apache.ibatis.session.SqlSession; public void testSelectStudentById() { SqlSession session = MyBatisUtil.getSqlSession(); StudentDao dao = session.getMapper(StudentDao.class); // 查询id为1009的学生信息 Student student = dao.selectStudentById(1009); System.out.println(student); // 关闭SqlSession对象 session.close(); }
2、参数
- 通过java程序把数据传入到mapper文件的SQL语句中,参数主要指dao接口方法的形参。
2.1 parameterType
-
parameterType:表示参数的类型,指定dao方法的形参数据类型。这个形参的数据类型是给mybatis使用的。mybatis在给SQL语句的参数赋值时使用。等同于JDBC中prepareStatement.setXXX(位置,值)。
-
当parameterType的类型是简单类型(8中基本(封装) + String), 则 #{} 可随意填写,如:
<select id="getById" parameterType="int" resultType="users"> ===>入参类型是简单类型 select id,username,birthday,sex,address from users where id=#{xxx} ===>随便写 </select>
-
当parameterType的类型是实体类的类型(如 Student类),则 #{} 内只能是类中的成员变量的名称,而且区分大小写。如:
<insert id="insert" parameterType="Student" > ===>入参是实体类 insert into users (id, name, email, age) values(#{id},#{name},#{email},#{age}) ==>成员变量名称 </insert> <!-- Student实体类如下: public class Student { private Integer id; private String name; private String email; private Integer age; getter…… setter…… …………………… } -->
2.2 当dao接口方法含一个简单参数时
-
dao接口如下:
// dao接口的函数,含有一个Integer类型的参数 // 查询一条记录 Student selectStudentById(Integer id);
-
mapper如下:
<!-- 根据id查询Student记录 --> <select id="selectStudentById" resultType="com.Etui.entity.Student"> select id,name,email,age from student where id = #{id} </select>
-
测试代码如下:
public void testSelectStudentById() { SqlSession session = MyBatisUtil.getSqlSession(); StudentDao dao = session.getMapper(StudentDao.class); Student student = dao.selectStudentById(1009); System.out.println(student); // 关闭SqlSession对象 session.close(); }
2.3 当dao接口方法含多个简单类型参数时
-
dao接口方法如下:
/* 多个简单类型的参数 使用@Param命名参数,注解是mybatis提供的 位置:在形参定义的前面 属性:value 自定义的参数名称,“value = ”可省略 */ // List<Student> selectByNameOrAge(@Param(value = "myName") String name, @Param(value = "myAge") Integer age); List<Student> selectByNameOrAge(@Param("myName") String name, @Param("myAge") Integer age);
-
mapper如下:
<!-- 多个简单类型的参数 当使用了@Param命名后,例如@Param(“myName”) 在mapper中,使用#{命名的参数}, 例如 #{myName} --> <select id="selectByNameOrAge" resultType="com.Etui.entity.Student"> select * from student where name = #{myName} or age = #{myAge} </select>
-
测试代码如下:
public void testSelectByNameOrAge() { SqlSession session = MyBatisUtil.getSqlSession(); StudentDao dao = session.getMapper(StudentDao.class); List<Student> students = dao.selectByNameOrAge("刻晴", 18); students.forEach(System.out::println); session.close(); }
2.4 当dao接口方法使用一个对象作为参数时
-
dao方法如下:
// 插入一条记录, 以Student对象作为参数 Integer insertStudent(Student student);
-
mapper如下:
<!-- 插入一条记录(parameterType为参数类型) --> <!-- 此处参数为一个Student对象 此时下方SQL语句中的占位符(id/name/email/age)均为Student对象中的属性。 --> <insert id="insertStudent" parameterType="com.Etui.entity.Student"> insert into student(id,name,email,age) values(#{id}, #{name}, #{email}, #{age}) </insert>
-
测试代码:
public void testInsertStudent() { SqlSession session = MyBatisUtil.getSqlSession(); StudentDao dao = session.getMapper(StudentDao.class); Student student = new Student(null, "香菱", "xiangling@qq.com", 19); Integer result = dao.insertStudent(student); System.out.println(result == 1 ? "添加成功!" : "添加失败!"); // 提交事务 session.commit(); session.close(); };
2.5 多个简单类型参数,使用“位置”
-
dao方法如下:
// 通过位置获取参数值 List<Student> selectStudentByPosition(String name, Integer age);
-
mapper如下:
<!-- 使用位置获取参数值,dao接口方法是多个简单类型的参数 语法: #{arg0} , #{arg1} …… --> <select id="selectStudentByPosition" resultType="com.Etui.entity.Student"> select * from student where name = #{arg0} or age = #{arg1} </select>
-
测试代码:
public void testSelectStudentByPosition() { SqlSession session = MyBatisUtil.getSqlSession(); StudentDao dao = session.getMapper(StudentDao.class); List<Student> students = dao.selectStudentByPosition("刻晴", 18); students.forEach(System.out::println); session.close(); }
2.6 当参数为Map时
-
dao方法如下:
// 通过Map对象获取参数值 List<Student> selectStudentByMap(Map<String, Object> data);
-
mapper如下:
<!-- 使用Map对象传递参数 在mapper文件中,获取map的值,是通过key获取的,语法:#{key} --> <select id="selectStudentByMap" resultType="com.Etui.entity.Student"> select * from student where name = #{name} or age = #{age} </select>
-
测试代码:
public void testSelectStudentByMap() { SqlSession session = MyBatisUtil.getSqlSession(); StudentDao dao = session.getMapper(StudentDao.class); // 创建Map对象并添加数据 Map<String, Object> data = new HashMap<>(); data.put("name", "刻晴"); data.put("age", 22); List<Student> students = dao.selectStudentByMap(data); students.forEach(System.out::println); session.close(); }
3、#{} 和 ${} 的区别
3.1 #{} 占位符的特点
- 使用prepareStatement对象执SQL语句,效率高。
- 使用prepareStatement对象,能避免SQL注入,SQL语句执行更安全。
- #{} 常常作为列值使用,位于等号的右侧,#{}位置的值是和数据类型有关的。
3.2 ${} 的特点
- 使用Statemet对象执行SQL语句,效率低。
- ${} 占位符的值,使用的字符串连接方式,有SQL注入的风险。有代码安全问题。
- ${} 数据是原样使用的,不会区分数据类型。
- ${} 常用作 表名 或 列名 ,在能保证数据安全的情况下使用。
4、封装MyBatis输出结果
4.1 resultType
- resultType:执行SQL得到ResultSet转换的类型,使用类型的完全限定名或别名。
- 如果返回的是集合,应当设置为集合包含的类型,而不是集合本身。
- resultType与resultMap不能同时使用
4.1.1 resultType为简单类型(以int为例)
-
dao接口方法如下:
// 查询表中的记录数 long getCounts();
-
mapper如下:
<select id="getCounts" resultType="java.lang.Long"> select count(*) from student </select>
-
测试代码如下:
@Test public void testGetCounts() { SqlSession session = MyBatisUtil.getSqlSession(); StudentDao dao = session.getMapper(StudentDao.class); Long result = dao.getCounts(); System.out.println("counts = " + result); // 关闭SqlSession对象 session.close(); }
4.1.2 resultType为对象类型(以Student类为例)
-
dao接口方法如下:
// 查询一条记录 Student selectStudentById(Integer id);
-
mapper如下:
<!-- 根据id查询Student记录 --> <select id="selectStudentById" resultType="com.Etui.entity.Student"> select * from student where id = #{id} </select>
-
测试代码如下:
@Test public void testSelectStudentById() { SqlSession session = MyBatisUtil.getSqlSession(); StudentDao dao = session.getMapper(StudentDao.class); Student student = dao.selectStudentById(1009); System.out.println(student); // 关闭SqlSession对象 session.close(); }
4.1.3 resultType为Map类型
-
SQL的查询结果为Map的key和value。推荐使用Map<Object, Object>。
-
注:Map作为接口返回值,SQL语句的查询结果最多只能有一条记录。
-
dao接口如下:
// 当返回值为Map时 Map<Object, Object> selectMap(Integer id);
-
mapper如下:
<!-- 执行SQL得到一个Map结构数据,mybatis执行SQL,把ResultSet转换为Map sql执行结果,列名叫做map的key, 列值为map的value。 SQL执行得到是一个记录,转换为map结构是正确的 dao接口返回是一个map, SQL语句最多能获取一条记录,多行则报错 --> <select id="selectMap" resultType="java.util.HashMap"> select * from student where id = #{id} </select>
-
测试代码:
@Test public void testSelectMap() { SqlSession session = MyBatisUtil.getSqlSession(); StudentDao dao = session.getMapper(StudentDao.class); Map<Object, Object> data = dao.selectMap(1009); System.out.println("name = " + data.get("name")); System.out.println("age = " + data.get("age")); // 关闭SqlSession对象 session.close(); }
4.2 resultMap
-
resultMap: 结果映射。自定义别名和java对象属性的对应关系。常用在列名和属性名不同的情况。使用方法如下:
- 先定义resultMap标签,指定列名和属性名称的对应关系。
- 在select标签时用resultMap属性,指定上面定义resultMap的id值。
-
实例:
-
已知Customer类与Student类含有相同的属性和方法,但属性名和方法名不同,如下:
package com.Etui.entity; public class Customer { private Integer sId; private String sName; private String sEmail; private Integer sAge; …… …… …… }
-
Student类如下:
package com.Etui.entity; public class Student { private Integer id; private String name; private String email; private Integer age; …… …… …… }
-
StudentDao接口中的方法如下:
// 查询一条记录 Customer selectStudentById2(Integer id);
-
StudentDao.xml文件中的对应SQL如下:
<!-- 使用resultMap定义列和属性的关系 --> <!-- 定义resultMap id:给resultMap的映射关系起个名称,唯一值 type:java类型的全限定名称 当类名和属性名相同时不用定义 --> <resultMap id="customMap" type="com.Etui.entity.Customer"> <!-- 定义列名和属性名的对应 --> <!-- 主键类型使用id标签 --> <id column="id" property="sId" /> <!-- 非主键类型使用result标签 --> <result column="name" property="sName" /> <result column="email" property="sEmail" /> <result column="age" property="sAge" /> </resultMap> <!-- 使用resultMap属性,指定映射关系的id --> <select id="selectStudentById2" resultMap="customMap"> select * from student where id = #{id} </select>
-
测试代码如下:
@Test public void testSelectStudentById2() { SqlSession session = MyBatisUtil.getSqlSession(); StudentDao dao = session.getMapper(StudentDao.class); Customer customer = dao.selectStudentById2(1009); System.out.println(customer); // 关闭SqlSession对象 session.close(); }
-
运行结果如下:
-
由查询结果可以看出,结果为Customer类的实例,且与Student类不同属性名的属性值未被赋值为空。
-
4.3 列名和java对象属性名不一样的解决方式
-
1、通过resultMap实现。
-
2、通过SQL语句中的别名实现。实现与上文案例相同的功能,mapper如下:
-
<!-- 使用列别名,解决列名和属性名不同的问题 --> <select id="selectStudentById3" resultType="com.Etui.entity.Customer"> select id sId, name sName, email sEmail, age Sage from student where id = #{id} </select>
-
4.4 模糊查询(like)
-
模糊查询的实现有两种方式,一是java代码中给查询数据加上”%“;二是在mapper文件SQL语句的条件位置加上”%“。
-
案例如下,查询“网”姓同学:
-
dao接口方法如下:
// 查询指定姓氏的同学(方式一) List<Student> selectByLike1(String lastname); // 查询指定姓氏的同学(方式二) List<Student> selectByLike2(String lastname);
-
方式一mapper如下:
<!-- 模糊查询(方式一) --> <select id="selectByLike1" resultType="com.Etui.entity.Student"> select * from student where name like "%" #{name} "%" </select>
-
方式一测试代码如下:
@Test public void testSelectByLike1() { SqlSession session = MyBatisUtil.getSqlSession(); StudentDao dao = session.getMapper(StudentDao.class); List<Student> students = dao.selectByLike1("王"); students.forEach(System.out::println); // 关闭SqlSession对象 session.close(); }
-
方式二mapper如下:
<!-- 模糊查询(方式二) --> <select id="selectByLike2" resultType="com.Etui.entity.Student"> select * from student where name like #{name} </select>
-
方式二测试代码如下:
@Test public void testSelectByLike2() { SqlSession session = MyBatisUtil.getSqlSession(); StudentDao dao = session.getMapper(StudentDao.class); String lastname = "%王%"; List<Student> students = dao.selectByLike2(lastname); students.forEach(System.out::println); // 关闭SqlSession对象 session.close(); }
-