dongxurr 2020-08-08
//4.执行映射配置文件中的sql语句,并接收结果 list = sqlSession.selectList("StudentMapper.selectAll");
//4.获取StudentMapper接口的实现类对象 StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); //5.通过实现类对象调用方法,接收结果 result = mapper.delete(id);
两者其实并无区别,只不过StudentMapper利用代理对象操作sqlSession.selectList();
<mapper namespace="StudentMapper">
<mapper namespace="com.zhu.mapper.StudentMapper">
1.完全限定名(比如“com.mypackage.MyMapper.selectAllThings”)将被直接查找并且找到即用。
2.短名称(比如“selectAllThings”)如果全局唯一也可以作为一个单独的引用。如果不唯一,有两个或两个以上的相同名称(比如“com.foo.selectAllThings ”和“com.bar.selectAllThings”),那么使用时就会收到错误报告说短名称是不唯一的,这种情况下就必须使用完全限定名。
Mybatis中namespace用于绑定dao接口,dao接口的方法对应mapper中的sql语名
1)映射配置文件中的名称空间必须和Dao层接口的全类名相同
2)映射配置文件中的增删改查的标签id属性必须和Dao层接口层的方法名相同
3)映射配置文件中的增删改查标签的parameterType属性必须和Dao层接口方法的参数相同
4)映射配置文件中的增删改查标签的resultType属性必须和Dao层接口方法的返回值相同
1)删除mapper层接口的实现类
2)修改映射配置文件
3)修改service层接口的实现类,采用接口代理方式实现功能
在写StudentMapper.java时
注意
1、
resultType="student"
方法的返回值为List<Student>
2、
parameterType="student"
方法的参数为Student student
3、如何取出参数中的值 #{}
<?xml version="1.0" encoding="UTF-8" ?> <!--MyBatis的DTD约束--> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties resource="jdbc.properties"/> <settings> <setting name="logImpl" value="log4j"/> </settings> <!--默认名为类名首字母小写--> <typeAliases> <package name="com.zhu.bean"/> </typeAliases> <environments default="mysql"> <!--environment配置数据库环境 id 属性唯一标识 --> <environment id="mysql"> <!-- transactionManager事务管理。type属性,采用JDBC默认的事务--> <transactionManager type="JDBC"></transactionManager> <!--dataSource数据源信息 type属性 连接池 MyBatis默认有三种数据源--> <dataSource type="POOLED"> <!--property获取数据库连接的配置信息--> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <!-- mappers引入映射配置文件 --> <mappers> <!-- mapper 引入指定的映射配置文件 resource属性指定映射配置文件的名称 --> <mapper resource="StudentMapper.xml"/> </mappers> </configuration>
<?xml version="1.0" encoding="UTF-8" ?> <!--MyBatis的DTD约束--> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- mapper: 核心根标签 namespace属性: 名称空间 --> <mapper namespace="com.zhu.mapper.StudentMapper"> <select id="selectAll" resultType="student"> SELECT * FROM student </select> <insert id="insert" parameterType="student"> INSERT INTO student VALUES (#{id},#{name},#{age}); </insert> <delete id="delete" parameterType="int"> DELETE FROM student WHERE id=#{id}; </delete> </mapper>
public class StudentController { private StudentService studentService = new StudentServiceImpl(); @Test public void selectAll(){ List<Student> list = studentService.selectAll(); for (Student student : list) { System.out.println(student); } } @Test public void insert(){ Student st = new Student(10,"路飞",23); Integer insert = studentService.insert(st); System.out.println(insert); } @Test public void delete(){ Integer s = 3; Integer i = studentService.delete(3); System.out.println(i); } }
public interface StudentMapper{ /* 注意: resultType 值为 student 指定结果映射的对象类型 方法的返回值为 List<Student> resultType: 1、基本类型 :resultType=基本类型 2、List类型 :resultType=List中元素的类型 3、Map类型 单条记录:resultType =map 多条记录:resultType =Map中value的类型 方法的返回值可以为List<Student> parameterType: 基本数据类型:int,string,long,Date; 复杂数据类型:类和Map 如何获取参数中的值: 基本数据类型:#{value}或${value} 获取参数中的值 复杂数据类型:#{属性名}或${属性名} ,map中则是#{key}或${key} */ public abstract List<Student> selectAll(); Integer insert(Student student); Integer delete(Integer integer); }
public interface StudentService { List<Student> selectAll(); Integer insert(Student student); Integer delete(Integer integer); }
public class StudentServiceImpl implements StudentService { @Override public List<Student> selectAll() { List<Student> list = null; SqlSession sqlSession = null; InputStream is = null; try { is = Resources.getResourceAsStream("MyBatisConfig.xml"); SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); sqlSession = factory.openSession(true); //获取StudentMapper接口的实现类对象 //获取对应的Mapper,让映射器通过命名空间和方法名称找到对应的SQL,发送给数据库执行后返回结果。 //操作数据库主要是通过SQL语句,那么只要找到SQL语句然后执行不就可以 //sqlSession.getMapper()的内部产生了StudentMapper的实现类,那怎么产生的呢? //动态代理 /* 被代理对象:真实的对象 代理对象:内存中的一个对象 */ StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); //StudentMapper studentMapper1 = new StudentServiceImpl(); //return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy); /* 类加载器:和被代理对象使用相同的类加载器 接口类型Class数组:和被代理对象使用相同接口 代理规则:完成代理增强的功能 */ //通过代理对象调用方法,接收结果 list = mapper.selectAll(); } catch (IOException e) { e.printStackTrace(); }finally { if(sqlSession != null) { sqlSession.close(); } if(is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } return list; }
通过动态代理开发模式,我们只编写一个接口,不写实现类,我们通过getMapper() 方法最终获取到 org.apache.ibatis.binding.MapperProxy代理对象,然后执行功能,而这个代理对象正是 MyBatis使用了 JDK 的动态代理技术,帮助我们生成了代理实现类对象。从而可以进行相关持久化操作。
动态代理实现类对象在执行方法的时候最终调用了mapperMethod.execute() 方法,这个方法中通过 switch 语句根据操作类型来判断是新增、修改、删除、查询操作,最后一步回到了MyBatis 最原生的 SqlSession方式来执行增删改查。
原生:Dao ---> DaoImpl
接口:Mapper ---> xxMapper.xml
接口代理方式可以让给我们只编写接口即可,而实现类对象由MyBatis生成
获取动态代理对象
SqlSession功能类中的getMapper(Mapper接口.class)方法。
<select id="selectCondition" resultType="student" parameterType="student"> SELECT * FROM student <where> <if test="id != null"> id = #{id} </if> <if test="name != null"> AND name = #{name} </if> <if test="age != null"> AND age = #{age} </if> </where> </select>
foreach 用来迭代用户传过来的List或者Array
如:使用foreach元素来构建in子语句
collection
: 指定要遍历的集合名称 list、array
item
: 用来临时存放迭代集合中当前元素的值,便于在foreach中使用
open
:将该属性指定的值添加到foreach迭代后拼出字符串的开始
close
:将该属性指定的值添加到foreach迭代拼出字符串的结尾
separator
: 用来分割foreach元素迭代的每个元素
<!--SELECT * FROM student WHERE id IN (1,2); --> <select id="selectByIds" resultType="student" parameterType="list"> SELECT * from student <where> <foreach collection="list" open="id IN(" close=")" item="id" separator=","> #{id} </foreach> </where> </select> <select id="selectByIds2" resultType="student" parameterType="list"> SELECT * from student where id IN <foreach collection="list" open="(" close=")" item="id" separator=","> #{id} </foreach> </select> <!--如果是 selectById(List<Student> stus) 这种--> <select id="selectByIds3" resultType="student" parameterType="list"> SELECT * from student <where> <foreach collection="list" open="id IN(" close=")" item="stu" separator=","> #{stu.id} </foreach> </where> </select>
使用
StudentMapper.java
List<Student> selectByIds(List<Integer> list);
StudentService.java
List<Student> selectByIds(List<Integer> list);
<sql id="select">SELECT * FROM student</sql>
使用
<include refid="select"/>
使用PageHelper
(1) 导入jar包 分页插件pagehelper-5.1.10.jar 和依赖的包 jsqlparser-3.1.jar
(2) 在核心配置文件中集成分页助手插件
(3) 在测试类中使用分页助手相关API实现分页功能。
MyBatisConfig.xml
<!-- 环境配置顺序 <!ELEMENT configuration (properties?, settings?, typeAliases?, typeHandlers?, objectFactory?, objectWrapperFactory?, reflectorFactory?, plugins?, environments?, databaseIdProvider?, mappers?)> --> <plugins> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins>
StudentServiceImpl.java
PageHelper.startPage(1,3); 一定要写在SQL执行之前
//通过分页助手来实现分页功能 // 第一页:显示3条数据 //PageHelper.startPage(1,3); // 第二页:显示3条数据 //PageHelper.startPage(2,3); // 第三页:显示3条数据 PageHelper.startPage(3,3); //5.调用实现类的方法,接收结果 List<Student> list = mapper.selectAll();PageHelper.startPage(0,1);
相关API
返回值 | 方法名 | 说明 |
---|---|---|
long | getTotal() | 获取总条数 |
int | getPages() | 获取总页数 |
int | getPageNum() | 获取当前页 |
int | getPageSize() | 获取每页显示条数 |
int | getPrePage() | 获取上一页 |
int | getNextPage() | 获取下一页 |
boolean | isIsFirstPage() | 获取是否是第一页 |
boolean | isIsLastPage() | 获取是否是最后一页 |
外键字段的建立是体现表与表关系的所在
用户基本信息表 和 用户详细信息表
店铺表 和 商品表
用户表 和 订单表
学生表 和 课程表
用户表 和 兴趣爱好表
模型 : 人和身份证 、 一个人只有一张身份证
数据准备
CREATE DATABASE db2; CREATE TABLE person( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20), age INT ); INSERT INTO person VALUES (NULL,‘张三‘,23); INSERT INTO person VALUES (NULL,‘李四‘,24); INSERT INTO person VALUES (NULL,‘王五‘,25); CREATE TABLE card( id INT PRIMARY KEY AUTO_INCREMENT, number VARCHAR(30), pid INT, CONSTRAINT cp_fk FOREIGN KEY (pid) REFERENCES person(id) ) INSERT INTO card VALUES (NULL,‘12345‘,1); INSERT INTO card VALUES (NULL,‘23456‘,2); INSERT INTO card VALUES (NULL,‘34567‘,3);
bean
Student.java
public class Person { private Integer id; //主键id private String name; //人的姓名 private Integer age; //人的年龄 }
Card.java
public class Card { private Integer id; private String number; private Person p; }
OneToOneMapper.xml
<mapper namespace="com.mybatis.oneToOne.OneToOneMapper"> <!-- <resultMap>是Mybatis的结果集封装 --> <!--通过 <resultMap>: 配置字段和对象属性的映射关系标签 属性 id 属性:resultMap 的唯一标识,此 id 值用于 select 元素 resultMap 属性的引用。 type 属性:表示该 resultMap 的映射结果类型(通常是 Java 实体类)。 子节点 id 子节点:一般对应数据库中该行的主键 id,设置此项可以提升 MyBatis 性能。 配置主键映射关系标签 result 子节点:映射到 JavaBean 的某个 “简单类型” 属性,如基础数据类型、包装类等。 配置非主键映射关系标签 子节点属性 column 属性:表示从数据库中查询的字段名或别名。表中字段名称 property 属性:表示查询出来的字段对应的值赋给实体对象的哪个属性。实体对象变量名称 说明:子节点 id 和 result 均可实现最基本的结果集映射,将列映射到简单数据类型的属性。 这两者唯一不同的是:在比较对象实例时 id 将作为结果集的标识属性。 这有助于提高总体性能,特别是应用缓存和嵌套结果映射的时候。 而若要实现高级结果映射,就需要学习下面两个配置项: association 和 collection。 association:映射到 JavaBean 的某个 “复杂类型” 属性,比如 JavaBean 类, 即 JavaBean 内部嵌套一个复杂数据类型(JavaBean)属性,这种情况就属于复杂类型的关联。 但是需要注意: association 仅处理一对一的关联关系。 association:配置被包含对象的映射关系 property:被包含对象的变量名 javaType:被包含对象的数据类型 --> <resultMap id="oneToOne" type="card"> <id column="cid" property="id"/> <result column="number" property="number"/> <association property="p" javaType="person"> <id column="pid" property="id"/> <result column="name" property="name"/> <result column="age" property="age"/> </association> </resultMap> <select id="selectAll" resultMap="oneToOne"> SELECT c.id cid, number, pid, NAME, age FROM card c , person p WHERE c.pid = p.id </select> </mapper>
MyBatisConfig.xml
<mappers> <!-- mapper 引入指定的映射配置文件 resource属性指定映射配置文件的名称 --> <mapper resource="com/mybatis/oneToOne/OneToOneMapper.xml"></mapper> </mappers>
测试
//4.获取OneToOneMapper接口的实现类对象 OneToOneMapper mapper = sqlSession.getMapper(OneToOneMapper.class); //5.调用实现类的方法,接收结果 List<Card> list = mapper.selectAll(); //6.处理结果 for (Card c : list) { System.out.println(c); }
数据准备
多表操作 一对多 班级对学生 CREATE TABLE classes( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARBINARY(20) ); INSERT INTO classes VALUES (NULL,‘s一班‘); INSERT INTO classes VALUES (NULL,‘s二班‘); CREATE TABLE student( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(30), age INT, cid INT, CONSTRAINT cs_fk FOREIGN KEY (cid) REFERENCES classes(id) ); INSERT INTO student VALUES (NULL,‘张三‘,23,1); INSERT INTO student VALUES (NULL,‘李四‘,24,1); INSERT INTO student VALUES (NULL,‘王五‘,25,2); INSERT INTO student VALUES (NULL,‘赵六‘,26,2);
bean
public class Student { private Integer id; private String name; private Integer age; }
public class Classes { private Integer id; private String name; private List<Student> students; //班级中所有学生对象 }
OneToManyMapper.xml
<mapper namespace="com.mybatis.oneToMany.OneToManyMapper"> <resultMap id="oneToMany" type="classes"> <id column="cid" property="id"/> <result column="cname" property="name"/> <!-- collection:配置被包含的集合对象映射关系 property:被包含对象的变量名 ofType:被包含对象的实际数据类型 --> <collection property="students" ofType="student"> <id column="sid" property="id"/> <result column="sname" property="name"/> <result column="sage" property="age"/> </collection> </resultMap> <select id="selectAll" resultMap="oneToMany"> SELECT c.id cid, c.name cname, s.id sid, s.name sname, s.age sage FROM classes c,student s WHERE c.id=s.cid </select>
测试
//4.获取OneToManyMapper接口的实现类对象 OneToManyMapper mapper = sqlSession.getMapper(OneToManyMapper.class); //5.调用实现类的方法,接收结果 List<Classes> classes = mapper.selectAll(); //6.处理结果 for (Classes cls : classes) { System.out.println(cls.getId() + "," + cls.getName()); List<Student> students = cls.getStudents(); for (Student student : students) { System.out.println("\t" + student); } }
数据准备
学生和课程 一个学生可以选择多门课程 一个课程可以被多个学生选择
CREATE TABLE course( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20) ); INSERT INTO course VALUES (NULL,‘语文‘); INSERT INTO course VALUES (NULL,‘数学‘); CREATE TABLE stu_cr( id INT PRIMARY KEY AUTO_INCREMENT, sid INT, cid INT, CONSTRAINT sc_fk1 FOREIGN KEY (sid) REFERENCES student(id), CONSTRAINT sc_fk2 FOREIGN KEY (cid) REFERENCES course(id) ); INSERT INTO stu_cr VALUES (NULL,1,1); INSERT INTO stu_cr VALUES (NULL,1,2); INSERT INTO stu_cr VALUES (NULL,2,1); INSERT INTO stu_cr VALUES (NULL,2,2);
bean
Course.java
public class Course { private Integer id; private String name; }
Student.java
public class Student { private Integer id; private String name; private Integer age; private List<Course> courses; //学生所选的课程集合 }
ManyToManyMapper.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="com.mybatis.manyToMany.ManyToManyMapper"> <resultMap id="ManyToMany" type="student"> <id column="sid" property="id"/> <result column="sname" property="name"/> <result column="sage" property="age"/> <!-- <collection>:配置被包含集合对象的映射关系标签。 属性: property 属性:被包含集合对象的变量名 ofType 属性:集合中保存的对象数据类型--> <collection property="courses" ofType="course"> <id column="cid" property="id"/> <result column="cname" property="name"/> </collection> </resultMap> <select id="selectAll" resultMap="ManyToMany"> SELECT sc.sid, s.name sname, s.age sage, sc.cid, c.name cname FROM student s,course c,stu_cr sc WHERE sc.sid=s.id AND sc.cid=c.id </select> </mapper>
处理结果
//5.调用实现类的方法,接收结果 List<Student> students = mapper.selectAll(); //6.处理结果 for (Student student : students) { System.out.println(student.getId() + "," + student.getName() + "," + student.getAge()); List<Course> courses = student.getCourses(); for (Course cours : courses) { System.out.println("\t" + cours); } }
<!--一对一 所有标签如下 <resultMap>:配置字段和对象属性的映射关系标签。 属性: id 属性:唯一标识 type 属性:实体对象类型 <id>:配置主键映射关系标签。 <result>:配置非主键映射关系标签。 属性: column 属性:表中字段名称 property 属性: 实体对象变量名称 (*)<association>:配置被包含对象的映射关系标签。 属性: property 属性:被包含对象的变量名 javaType 属性:被包含对象的数据类型 --> <!--多对多 & 一对多 所有标签如下 <resultMap>:配置字段和对象属性的映射关系标签。 属性: id 属性:唯一标识 type 属性:实体对象类型 <id>:配置主键映射关系标签。 <result>:配置非主键映射关系标签。 属性: column 属性:表中字段名称 property 属性: 实体对象变量名称 (*)<collection>:配置被包含集合对象的映射关系标签。 属性: property 属性:被包含集合对象的变量名 ofType 属性:集合中保存的对象数据类型 -->
针对结果集而创建对应的javabean类,来接收结果集数据,这种javabean在领域驱动模型中称之为 : VO