Java SSM篇3——Mybatis

1、JDBC存在的问题

  • 数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能
  • sql 语句在代码中硬编码,造成代码不易维护,实际应用 sql 变化的可能较大,sql 变动需要改变java 代码
  • 查询操作时,需要手动将结果集中的数据手动封装到实体中

2、解决方案

  • 数据库连接池
  • 配置文件
  • 反射、内省

3、ORM是什么

对象关系映射

  • O(对象模型): 实体对象,即我们在程序中根据数据库表结构建立的一个个实体javaBean
  • R(关系型数据库的数据结构): 关系数据库领域的Relational(建立的数据库表)
  • M(映射): 从R(数据库)到O(对象模型)的映射,可通过XML文件映射

3、Mybatis简介

MyBatis是一个优秀的基于ORM的半自动轻量级持久层框架,它对jdbc的操作数据库的过程进行封装, 使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建 statement、手动设置参数、结果集检索等jdbc繁杂的过程代码

mybatis 官方文档:https://mybatis.org/mybatis-3/

4、mybatis快速入门

4.1、数据库准备

CREATE TABLE person(id INT PRIMARY KEY,NAME VARCHAR(10),PASSWORD VARCHAR(10)
);
INSERT INTO person VALUES (1,"root","123");

4.2、创建maven工程,pom.xml导入依赖

<dependencies><!--mybatis--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.5</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.20</version></dependency><!--junit--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13</version><scope>test</scope></dependency>
</dependencies>

pom设置资源过滤

<!--maven过滤问题-->
<build><resources><resource><directory>src/main/java</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource><resource><directory>src/main/resources</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource></resources>
</build>

4.3、数据库配置文件(database.properties)

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://132.232.82.49:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone =Asia/Shanghai
username=root
password=root

4.4、mybatis配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!--引入properties配置文件--><properties resource="database.properties"></properties><!--别名--><typeAliases><package name="club.winkto.bean"></package></typeAliases><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment></environments><!--注册映射文件--><mappers><package name="club.winkto.mapper"/></mappers>
</configuration>

4.5、实体类

public class Person {private int id;private String name;private String password;
}

4.6、Mapper接口

public interface PersonMapper {ArrayList<Person> selectPerson();int insertPerson(Person person);int updatePerson(Person person);int deletePerson(int id);
}

4.7、映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="club.winkto.mapper.PersonService"><select id="selectPerson" resultType="Person">select * from person;</select><insert id="insertPerson" parameterType="Person">insert into person values (#{id},#{name},#{password});</insert><update id="updatePerson" parameterType="Person">update person set name=#{name},password=#{password} where id=#{id};</update><delete id="deletePerson" parameterType="int">delete from person where id=#{id};</delete>
</mapper>

4.8、mybatis工具类

public class MybatisUtils {private static SqlSessionFactory sqlSessionFactory=null;static{String resource = "mybatis_config.xml";InputStream inputStream = null;try {inputStream = Resources.getResourceAsStream(resource);} catch (IOException e) {e.printStackTrace();}sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);}public static SqlSession getSqlSession(){return sqlSessionFactory.openSession();}
}

4.9、测试类

public class CRUD {@Testpublic void select(){SqlSession sqlSession = MybatisUtils.getSqlSession();PersonService mapper = sqlSession.getMapper(PersonService.class);ArrayList<Person> people = mapper.selectPerson();for (Person person : people) {System.out.println(person);}System.out.println("========================");sqlSession.close();}@Testpublic void insert(){SqlSession sqlSession = MybatisUtils.getSqlSession();PersonService mapper = sqlSession.getMapper(PersonService.class);int i = mapper.insertPerson(new Person(2, "bingbing", "123"));if (i>0){sqlSession.commit();}sqlSession.close();}@Testpublic void update(){SqlSession sqlSession = MybatisUtils.getSqlSession();PersonService mapper = sqlSession.getMapper(PersonService.class);int i = mapper.updatePerson(new Person(2, "bingbing", "blingbling"));if (i>0){sqlSession.commit();}sqlSession.close();}@Testpublic void delete(){SqlSession sqlSession = MybatisUtils.getSqlSession();PersonService mapper = sqlSession.getMapper(PersonService.class);int i = mapper.deletePerson(2);if (i>0){sqlSession.commit();}sqlSession.close();}@Testpublic void doCRUD(){select();insert();select();update();select();delete();select();}
}

5、Mybatis配置解析

  • properties
  • settings
  • typeAliases
  • typeHandlers
  • objectFactory
  • plugins
  • environments
    • environment

      • transactionManager
      • dataSource
  • databaseIdProvider
  • mappers

5.1、properties

5.1.1、直接书写properties内容

<properties><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://132.232.82.49:3306/mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone =Asia/Shanghai"/><property name="username" value="root"/><property name="password" value="root"/>
</properties>

5.1.2、引入properties文件

<properties resource="database.properties"></properties>
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://132.232.82.49:3306/mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone =Asia/Shanghai
username=root
password=root

5.1.3、优先级问题

如果一个属性在多个地方出现,优先级为

  • 在方法体中给定的参数值
  • 在类路径或URL资源中读取的属性
  • 属性文件中的属性

5.2、settings

官方属性页:https://mybatis.org/mybatis-3/configuration.html#settings

<settings><!--全局启用或禁用在此配置下在任何映射器中配置的任何缓存--><setting name="cacheEnabled" value="true"/><!--全局启用或禁用延迟加载,启用时,将延迟加载所有关系,对于特定关系,可以使用fetchType属性替换该值--><setting name="lazyLoadingEnabled" value="true"/><!--允许或不允许从单个语句返回多个结果集--><setting name="multipleResultSetsEnabled" value="true"/><!--使用列标签而不是列名--><setting name="useColumnLabel" value="true"/><!--允许JDBC支持生成的密钥--><setting name="useGeneratedKeys" value="false"/><setting name="autoMappingBehavior" value="PARTIAL"/><setting name="autoMappingUnknownColumnBehavior" value="WARNING"/><setting name="defaultExecutorType" value="SIMPLE"/><!--驱动程序等待数据库响应的秒数--><setting name="defaultStatementTimeout" value="25"/><setting name="defaultFetchSize" value="100"/><setting name="safeRowBoundsEnabled" value="false"/><setting name="mapUnderscoreToCamelCase" value="false"/><setting name="localCacheScope" value="SESSION"/><setting name="jdbcTypeForNull" value="OTHER"/><setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/><!--日志方式--><setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

5.3、typeAliases

5.3.1、设置单个

<typeAliases><typeAlias type="com.yan.po.User" alias="user"/>
</typeAliases>

5.3.2、设置包

<typeAliases><package name="com.ruoye.bean"></package>
</typeAliases>

5.3.3、Mybatis设置好的类型别名

别名 类型
_byte byte
_long long
_short short
_int int
_integer int
_double double
_float float
_boolean boolean
string String
byte Byte
long Long
short Short
int Integer
integer Integer
double Double
float Float
boolean Boolean
date Date
decimal BigDecimal
bigdecimal BigDecimal
object Object
map Map
hashmap HashMap
list List
arraylist ArrayList
collection Collection
iterator Iterator

5.4、typeHandlers(类型句柄)

可以重写类型句柄或者是创建你自己的方式来处理不支持或者是非标准的类型,只需要简单地实现org.mybaits.type包里的TypeHandler,并且映射到一个JAVA类型,然后再选定一个JDBC类型

5.4.1、定义类型

<typeHandlers><typeHandler handler="RuoyeTypeHandler"/>
</typeHandlers>

5.4.2、实现TypeHandler

import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class RuoyeTypeHandler<T> implements TypeHandler<T> {public void setParameter(PreparedStatement preparedStatement, int i, T t, JdbcType jdbcType) throws SQLException {preparedStatement.setString(i, (String) t);}public T getResult(ResultSet resultSet, String s) throws SQLException {return null;}public T getResult(ResultSet resultSet, int i) throws SQLException {return null;}public T getResult(CallableStatement callableStatement, int i) throws SQLException {return null;}
}

5.4.3、使用

<resultMap type="" id="" ><result column="" property="" typeHandler="RuoyeTypeHandler"/>
</resultMap>

5.5、ObjectFactory

5.5.1、定义

<ObjectFactory type="RuoyeObjectFactory"><property name=""  value=""/>
</ObjectFactory>

5.5.2、继承DefaultObjectFactory

import org.apache.ibatis.reflection.factory.DefaultObjectFactory;import java.util.List;
import java.util.Properties;public class RuoyeObjectFactory extends DefaultObjectFactory {@Overridepublic <T> T create(Class<T> type) {return super.create(type);}@Overridepublic <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {return super.create(type, constructorArgTypes, constructorArgs);}public void setProperties(Properties properties) {}
}

5.6、plugins

<plugins><plugin interceptor="com.github.pagehelper.PageHelper"><!-- 设置数据库类型 Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL六种数据库-->        <property name="dialect" value="mysql"/></plugin>
</plugins>

5.7、environments

虽然你可以配置多重环境,但是你只可以选择一对一的SqlsessionFactory实例

<environments default="formal"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment><environment id="formal"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment>
</environments>

5.8、Mappers

5.8.1、单个映射

<mappers><mapper resource="club/winkto/mapper/PersonMapper.xml"/>
</mappers>
<mappers><!--路径以.分隔--><mapper class="club.winkto.mapper.PersonMapper"></mapper>
</mappers>

5.8.2、包映射

<mappers><package name="club.winkto.mapper"/>
</mappers>

6、注解开发(初步认识)

不再书写映射文件PersonMapper.xml

public interface PersonMapper {@Select("select * from person")ArrayList<Person> selectPerson();@Insert("insert into person values (#{id},#{name},#{password})")int insertPerson(Person person);@Update("update person set name=#{name},password=#{password} where id=#{id}")int updatePerson(Person person);@Delete("delete from person where id=#{id}")int deletePerson(@Param("id") int id);
}

注册class文件,当然你也可以注册包

<mappers><!--路径以/分隔--><mapper class="com.lancame.mapper.PersonService"></mapper>
</mappers>

7、结果集映射(初步认识)

resultType:如果实体的属性名与表中字段名一致,将查询结果自动封装到实体类中

<select id="selectPerson" resultType="Person">select * from person;
</select>

resutlMap:如果实体的属性名与表中字段名不一致,可以使用ResutlMap实现手动封装到实体类中

如果有查询结果有 字段与属性是对应的,可以省略手动封装
<resultMap id="PersonMap" type="Person"><!--id常用于主键列--><id column="id" property="id" /><!--result用于其他列--><result column="name" property="name" /><result column="password" property="password" />
</resultMap>
<select id="selectPerson" resultMap="PersonMap">select * from person;
</select>

8、参数传递

8.1、封装map传递

<select id="selectPerson1" parameterType="map" resultType="Person">select * from person where name=#{name} and password=#{password};
</select>
public interface PersonMapper {ArrayList<Person> selectPerson1(Map map);
}
@Test
public void select1(){SqlSession sqlSession = MybatisUtil.getSqlSession();PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);HashMap<String, Object> hashMap = new HashMap<String, Object>();hashMap.put("name","root");hashMap.put("password","123");ArrayList<Person> people = mapper.selectPerson1(hashMap);for (Person person : people) {System.out.println(person);}System.out.println("========================");sqlSession.close();
}

8.2、注解传递

<select id="selectPerson1" resultType="Person">select * from person where name=#{name} and password=#{password};
</select>
public interface PersonMapper {ArrayList<Person> selectPerson1(@Param("name") String name,@Param("password") String password);
}
@Test
public void select1(){SqlSession sqlSession = MybatisUtil.getSqlSession();PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);ArrayList<Person> people = mapper.selectPerson1("root","123");for (Person person : people) {System.out.println(person);}System.out.println("========================");sqlSession.close();
}

9、模糊查询

9.1、${} 与 #{}

  • 通过 #{} 可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,# {}可以有效防止sql注入

  • 通过 ${} 可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换,会出现sql注入问题

9.2、模糊查询操作

<select id="selectPerson2" parameterType="string" resultType="Person">select * from person where name like "%"#{name}"%"
</select>
public interface PersonMapper {ArrayList<Person> selectPerson2(String name);
}
@Test
public void select2(){SqlSession sqlSession = MybatisUtil.getSqlSession();PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);ArrayList<Person> people = mapper.selectPerson2("roo");for (Person person : people) {System.out.println(person);}System.out.println("========================");sqlSession.close();
}

9.3、返回主键

9.3.1、useGeneratedKeys

只适用于主键自增的数据库,mysql和sqlserver支持,oracle不行

<insert id="insertPerson1" parameterType="Person" useGeneratedKeys="true" keyProperty="id">insert into person (name,password) values (#{name},#{password});
</insert>
public interface PersonMapper {int insertPerson1(Person person);
}
@Test
public void insert1(){SqlSession sqlSession = MybatisUtil.getSqlSession();PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);Person bingbing = new Person(0, "bingbing", "123");int i = mapper.insertPerson1(bingbing);System.out.println(bingbing.getId());if (i>0){sqlSession.commit();}sqlSession.close();
}

9.3.2、selectKey

适用范围广,支持所有类型数据库

<insert id="insertPerson2" parameterType="Person">insert into person (name,password) values (#{name},#{password});<selectKey  keyColumn="id" keyProperty="id" resultType="int" order="AFTER">SELECT LAST_INSERT_ID();</selectKey>
</insert>
public interface PersonMapper {int insertPerson1(Person person);
}
@Test
public void insert2(){SqlSession sqlSession = MybatisUtil.getSqlSession();PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);Person bingbing = new Person(0, "bingbing", "123");int i = mapper.insertPerson1(bingbing);System.out.println(bingbing.getId());if (i>0){sqlSession.commit();}sqlSession.close();
}

10、动态SQL

当我们要根据不同的条件,来执行不同的sql语句的时候,需要用到动态sql

10.1、where、if

<select id="selectPerson3" resultType="Person">select * from person<where><if test="name!=null">and name=#{name}</if><if test="password!=null">and password=#{password}</if></where>
</select>
public interface PersonMapper {ArrayList<Person> selectPerson3(@Param("name") String name,@Param("password") String password);
}
@Test
public void select3(){SqlSession sqlSession = MybatisUtil.getSqlSession();PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);ArrayList<Person> people = mapper.selectPerson3(null,"123");for (Person person : people) {System.out.println(person);}System.out.println("========================");sqlSession.close();
}

10.2、set、if

<update id="updatePerson1" parameterType="Person">update person<set><if test="name!=null">name=#{name},</if><if test="password!=null">password=#{password},</if></set>where id=#{id};
</update>
public interface PersonMapper {int updatePerson1(Person person);
}
@Test
public void update1(){SqlSession sqlSession = MybatisUtil.getSqlSession();PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);int i = mapper.updatePerson1(new Person(2, "bingbing", "blingbling"));if (i>0){sqlSession.commit();}sqlSession.close();
}

10.3、Choose、when、otherwise

参考switch

<select id="selectPerson4" resultType="Person">select * from person<where><choose><when test="name!=null">and name=#{name}</when><otherwise>and password=123</otherwise></choose></where>
</select>
public interface PersonMapper {ArrayList<Person> selectPerson3(@Param("name") String name,@Param("password") String password);
}
@Test
public void select4(){SqlSession sqlSession = MybatisUtil.getSqlSession();PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);ArrayList<Person> people = mapper.selectPerson4(null,"123");for (Person person : people) {System.out.println(person);}System.out.println("========================");sqlSession.close();
}

10.4、foreach

<select id="selectPerson5" resultType="Person">select * from person<where>id in<foreach collection="list" open="(" close=")" item="id" separator=",">#{id}</foreach></where>
</select>
public interface PersonMapper {;ArrayList<Person> selectPerson5(ArrayList<Integer> arrayList);
}
@Test
public void select5(){SqlSession sqlSession = MybatisUtil.getSqlSession();PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);ArrayList<Integer> integers = new ArrayList<Integer>(Arrays.asList(1,5,6));ArrayList<Person> people = mapper.selectPerson5(integers);for (Person person : people) {System.out.println(person);}System.out.println("========================");sqlSession.close();
}

11、SQL片段

<update id="updatePerson1" parameterType="Person">update person<set><include refid="whereif"></include></set>where id=#{id};
</update>
<sql id="whereif"><if test="name!=null">name=#{name},</if><if test="password!=null">password=#{password},</if>
</sql>
public interface PersonMapper {int updatePerson1(Person person);
}
@Test
public void update1(){SqlSession sqlSession = MybatisUtil.getSqlSession();PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);int i = mapper.updatePerson1(new Person(2, "bingbing", "blingbling"));if (i>0){sqlSession.commit();}sqlSession.close();
}

12、分页插件

12.1、依赖导入

<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>3.7.5</version>
</dependency>
<dependency><groupId>com.github.jsqlparser</groupId><artifactId>jsqlparser</artifactId><version>0.9.1</version>
</dependency>

12.2、mybatis配置分页

<plugins><!-- 分页助手的插件 --><plugin interceptor="com.github.pagehelper.PageHelper"><!-- 指定方言 --><property name="dialect" value="mysql"/></plugin>
</plugins>

12.3、测试

@Test
public void select6(){SqlSession sqlSession = MybatisUtil.getSqlSession();PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);PageHelper.startPage(1,2);ArrayList<Person> people = mapper.selectPerson();for (Person person : people) {System.out.println(person);}System.out.println("========================");PageInfo<Person> pageInfo = new PageInfo<Person>(people);System.out.println("总条数:"+pageInfo.getTotal());System.out.println("总页数:"+pageInfo.getPages());System.out.println("当前页:"+pageInfo.getPageNum());System.out.println("每页显示长度:"+pageInfo.getPageSize());System.out.println("是否第一页:"+pageInfo.isIsFirstPage());System.out.println("是否最后一页:"+pageInfo.isIsLastPage());sqlSession.close();
}

13、多表查询(根据结果嵌套)

  • 一对一:人与身份证号的关系
  • 一对多:用户与订单的关系,一个用户可以有多个订单,但是一个订单只能有一个用户
  • 多对多:用户与课程的关系,一个用户可以选多个课程,一个课程可以被多个用户选择

13.1、一对一(多对一)

13.1.1、数据库准备

CREATE TABLE person(pid INT PRIMARY KEY AUTO_INCREMENT,pname VARCHAR(20),ppassword VARCHAR(20)
)
CREATE TABLE idnum(pid INT,idnum VARCHAR(18)
)
ALTER TABLE ID ADD CONSTRAINT t2 FOREIGN KEY (pid) REFERENCES person(pid);

13.1.2、实体类

public class IDNum {private int pid;private String idnum;
}
public class Person {private int pid;private String pname;private String ppassword;private IDNum idnum;
}

13.1.3、接口

public interface PersonMapper {List<Person> selectPersonWithID();
}

13.1.4、映射文件

  • 一对一使用association标签关联

  • property=“user” 封装实体的属性名

  • javaType=“user” 封装实体的属性类型

<resultMap id="PersonIDMap" type="Person"><id column="pid" property="pid" /><result column="pname" property="pname" /><result column="ppassword" property="ppassword" /><association property="idnum" javaType="IDNum"><id column="pid" property="pid" /><result column="idnum" property="idnum" /></association>
</resultMap>
<select id="selectPersonWithID" resultMap="PersonIDMap">select * from person,idnum where person.pid=idnum.pid
</select>

13.1.5、测试

@Test
public void test(){SqlSession sqlSession = MybatisUtil.getSqlSession();PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);List<Person> people = mapper.selectPersonWithID();for (Person person : people) {System.out.println(person);}
}

13.2、一对多

13.2.1、数据库准备

CREATE TABLE person(pid INT PRIMARY KEY AUTO_INCREMENT,pname VARCHAR(20),ppassword VARCHAR(20)
)
CREATE TABLE orders(pid INT,oid INT PRIMARY KEY AUTO_INCREMENT,otime DATETIME,oremark  VARCHAR(100)
)
ALTER TABLE orders ADD CONSTRAINT t1 FOREIGN KEY (pid) REFERENCES person(pid);

随便加几条数据

13.2.2、实体类

public class Person {private int pid;private String pname;private String ppassword;private List<Order> orders;
}
public class Order {private int pid;private int oid;private Date date;private String oremark;
}

13.2.3、接口

public interface PersonMapper {List<Person> selectPersonWithOrder();
}

13.2.4、映射文件

  • 一对多使用collection标签关联
  • property=“orderList” 封装到集合的属性名
  • ofType=“order” 封装集合的泛型类型
<resultMap id="PersonOrderMap" type="Person"><id column="pid" property="pid" /><result column="pname" property="pname" /><result column="ppassword" property="ppassword" /><collection property="orders" ofType="Order"><id column="oid" property="oid" /><result column="pid" property="pid" /><result column="otime" property="otime" /><result column="oremark" property="oremark" /></collection>
</resultMap>
<select id="selectPersonWithOrder" resultMap="PersonOrderMap">SELECT * FROM person LEFT JOIN orders ON person.pid=orders.pid
</select>

13.2.5、测试

@Test
public void test1(){SqlSession sqlSession = MybatisUtil.getSqlSession();PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);List<Person> people = mapper.selectPersonWithOrder();for (Person person : people) {System.out.println(person);}
}

13.3、多对多

13.3.1、数据库准备

CREATE TABLE person(pid INT PRIMARY KEY AUTO_INCREMENT,pname VARCHAR(20),ppassword VARCHAR(20)
)
CREATE TABLE course(cid INT PRIMARY KEY AUTO_INCREMENT,cname VARCHAR(20)
);
CREATE TABLE person_course(pid INT,cid INT
);
ALTER TABLE person_course ADD CONSTRAINT t3 FOREIGN KEY (pid) REFERENCES person(pid);
ALTER TABLE person_course ADD CONSTRAINT t4 FOREIGN KEY (cid) REFERENCES course(cid);

随便加几条数据

13.3.2、实体类

public class Person {private int pid;private String pname;private String ppassword;private List<Order> orders;
}
public class Course {private int cid;private String cname;
}

13.3.3、接口

public interface PersonMapper {List<Person> selectPersonWithCourse();
}

13.3.4、映射文件

  • 一对多使用collection标签关联
  • property=“orderList” 封装到集合的属性名
  • ofType=“order” 封装集合的泛型类型
<resultMap id="PersonCourseMap" type="Person"><id column="pid" property="pid" /><result column="pname" property="pname" /><result column="ppassword" property="ppassword" /><collection property="courses" ofType="Course"><id column="cid" property="cid" /><result column="cname" property="cname" /></collection>
</resultMap>
<select id="selectPersonWithCourse" resultMap="PersonCourseMap">SELECT * FROM personLEFT JOIN person_course ON person.pid=person_course.pidLEFT JOIN course ON person_course.cid=course.cid
</select>

13.3.5、测试

@Test
public void test2(){SqlSession sqlSession = MybatisUtil.getSqlSession();PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);List<Person> people = mapper.selectPersonWithCourse();for (Person person : people) {System.out.println(person);}
}

14、多表查询(根据查询嵌套)

14.1、一对一(多对一)

14.1.1、数据库准备

CREATE TABLE person(pid INT PRIMARY KEY AUTO_INCREMENT,pname VARCHAR(20),ppassword VARCHAR(20)
)
CREATE TABLE idnum(pid INT,idnum VARCHAR(18)
)
ALTER TABLE ID ADD CONSTRAINT t2 FOREIGN KEY (pid) REFERENCES person(pid);

14.1.2、实体类

public class IDNum {private int pid;private String idnum;
}
public class Person {private int pid;private String pname;private String ppassword;private IDNum idnum;
}

14.1.3、接口

public interface PersonMapper {List<Person> selectPersonWithID();
}

14.1.4、映射文件

  • 一对一使用association标签关联

  • property=“user” 封装实体的属性名

  • javaType=“user” 封装实体的属性类型

  • column传递的参数

  • select调用的查询语句

<resultMap id="PersonIDMap" type="Person"><id column="pid" property="pid" /><result column="pname" property="pname" /><result column="ppassword" property="ppassword" /><association property="idnum" javaType="IDNum" column="pid" select="selectID"></association>
</resultMap>
<select id="selectPersonWithID" resultMap="PersonIDMap">select * from person
</select>
<select id="selectID" resultType="IDNum">select * from idnum where idnum.pid=#{pid}
</select>

14.1.5、测试

@Test
public void test(){SqlSession sqlSession = MybatisUtil.getSqlSession();PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);List<Person> people = mapper.selectPersonWithID();for (Person person : people) {System.out.println(person);}
}

14.2、一对多

14.2.1、数据库准备

CREATE TABLE person(pid INT PRIMARY KEY AUTO_INCREMENT,pname VARCHAR(20),ppassword VARCHAR(20)
)
CREATE TABLE orders(pid INT,oid INT PRIMARY KEY AUTO_INCREMENT,otime DATETIME,oremark  VARCHAR(100)
)
ALTER TABLE orders ADD CONSTRAINT t1 FOREIGN KEY (pid) REFERENCES person(pid);

随便加几条数据

14.2.2、实体类

public class Person {private int pid;private String pname;private String ppassword;private List<Order> orders;
}
public class Order {private int pid;private int oid;private Date date;private String oremark;
}

14.2.3、接口

public interface PersonMapper {List<Person> selectPersonWithOrder();
}

14.2.4、映射文件

  • 一对多使用collection标签关联
  • property=“orderList” 封装到集合的属性名
  • ofType=“order” 封装集合的泛型类型
  • column传递的参数
  • select调用的查询语句
<resultMap id="PersonOrderMap" type="Person"><id column="pid" property="pid" /><result column="pname" property="pname" /><result column="ppassword" property="ppassword" /><collection property="orders" ofType="Order" column="pid" select="selectOrder"></collection>
</resultMap>
<select id="selectPersonWithOrder" resultMap="PersonOrderMap">SELECT * FROM person
</select>
<select id="selectOrder" parameterType="int" resultType="Order">SELECT * FROM orders where orders.pid=#{pid}
</select>

14.2.5、测试

@Test
public void test1(){SqlSession sqlSession = MybatisUtil.getSqlSession();PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);List<Person> people = mapper.selectPersonWithOrder();for (Person person : people) {System.out.println(person);}
}

14.3、多对多

14.3.1、数据库准备

CREATE TABLE person(pid INT PRIMARY KEY AUTO_INCREMENT,pname VARCHAR(20),ppassword VARCHAR(20)
)
CREATE TABLE course(cid INT PRIMARY KEY AUTO_INCREMENT,cname VARCHAR(20)
);
CREATE TABLE person_course(pid INT,cid INT
);
ALTER TABLE person_course ADD CONSTRAINT t3 FOREIGN KEY (pid) REFERENCES person(pid);
ALTER TABLE person_course ADD CONSTRAINT t4 FOREIGN KEY (cid) REFERENCES course(cid);

随便加几条数据

14.3.2、实体类

public class Person {private int pid;private String pname;private String ppassword;private List<Order> orders;
}
public class Course {private int cid;private String cname;
}

14.3.3、接口

public interface PersonMapper {List<Person> selectPersonWithCourse();
}

14.3.4、映射文件

  • 一对多使用collection标签关联
  • property=“orderList” 封装到集合的属性名
  • ofType=“order” 封装集合的泛型类型
  • column传递的参数
  • select调用的查询语句
<resultMap id="PersonCourseMap" type="Person"><id column="pid" property="pid" /><result column="pname" property="pname" /><result column="ppassword" property="ppassword" /><collection property="courses" ofType="Course" column="cid" select="selectCourse"></collection>
</resultMap>
<select id="selectPersonWithCourse" resultMap="PersonCourseMap">SELECT * FROM personLEFT JOIN person_course ON person.pid=person_course.pid
</select>
<select id="selectCourse" parameterType="int" resultType="Course">select * from course where course.cid=#{cid}
</select>

14.3.5、测试

@Test
public void test2(){SqlSession sqlSession = MybatisUtil.getSqlSession();PersonMapper mapper = sqlSession.getMapper(PersonMapper.class);List<Person> people = mapper.selectPersonWithCourse();for (Person person : people) {System.out.println(person);}
}

15、加载策略

就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据,延迟加载也称懒加载

延迟加载是基于查询嵌套来实现的

15.1、优点

先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表 速度要快

15.2、缺点

因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时 间,所以可能造成用户等待时间变长,造成用户体验下降

15.3、开启局部延迟加载

在association和collection标签中都有一个fetchType属性,通过修改它的值,可以修改局部的加载策略

  • fetchType=“lazy” 懒加载策略
  • fetchType=“eager” 立即加载策略
<resultMap id="PersonCourseMap" type="Person"><id column="pid" property="pid" /><result column="pname" property="pname" /><result column="ppassword" property="ppassword" /><collection property="courses" ofType="Course" column="cid" select="selectCourse" fetchType="lazy"></collection>
</resultMap>
<select id="selectPersonWithCourse" resultMap="PersonCourseMap">SELECT * FROM personLEFT JOIN person_course ON person.pid=person_course.pid
</select>
<select id="selectCourse" parameterType="int" resultType="Course">select * from course where course.cid=#{cid}
</select>

15.4、延迟加载触发策略

在配置了延迟加载策略后,发现即使没有调用关联对象的任何方法,但是在你调用当前对象的 equals、clone、hashCode、toString方法时也会触发关联对象的查询,可以在配置文件中使用lazyLoadTriggerMethods配置项覆盖掉上面四个方法

<settings><setting name="lazyLoadTriggerMethods" value="toString()"/>
</settings>

15.5、全局延迟加载

局部的加载策略优先级高于全局的加载策略

<settings><setting name="lazyLoadingEnabled" value="true"/>
</settings>

16、缓存

通过缓存策略来减少数据库的查询次数, 从而提高性能

16.1、一级缓存

一级缓存是SqlSession级别的缓存,是默认开启的

在参数和SQL完全一样的情况下,使用同一个SqlSession对象调用一个Mapper方法,往往只执行一次SQL,因为使用SelSession第一次查询后,MyBatis会将其放在缓存中,以后再查询的时 候,如果没有声明需要刷新,并且缓存没有超时的情况下,SqlSession都会取出当前缓存的数据,而不 会再次发送SQL到数据库

一级缓存是SqlSession范围的缓存,执行SqlSession的C(增加)U(更新)D(删除)操作,或者调 用clearCache()、commit()、close()方法,都会清空缓存

强制清空一级缓存

sqlSession.clearCache();

设置每次清空一级缓存

<select flushCache="true"></select>

16.2、二级缓存

二级缓存是namspace级别(跨sqlSession)的缓存,是默认不开启的

二级缓存的开启需要进行配置,实现二级缓存的时候,MyBatis要求返回的POJO必须是可序列化的。 也就是要求实现Serializable接口,配置方法很简单,只需要在映射XML文件配置 就可以开启 二级缓存了

二级缓存是mapper映射级别的缓存,多个SqlSession去操作同一个Mapper映射的sql语句,多个 SqlSession可以共用二级缓存,二级缓存是跨SqlSession的

mybatis的二级缓存因为是namespace级别,所以在进行多表查询时会产生脏读问题

16.2.1、mybatis核心配置开启二级缓存(默认开启,此步可以省略)

<settings><setting name="cacheEnabled" value="true"/>
</settings>

16.2.2、在mapper文件中加入

<cache></cache>

缓存参数配置

<cache  eviction="FIFO"flushInterval="60000"size="512"readOnly="true"/>

16.2.3、在select语句上开启二级缓存

标签中设置useCache=”true”代表当前这个statement要使用二级缓存

<select useCache="true"></select>

16.2.4、修改实体类

继承Serializable

17、注解(深度认识)

之前在映射文件中通过配置、、来实现复杂关系映射

使用注解开发后,我们可以使用 @Results、@Result,@One、@Many 注解组合完成复杂关系的配置

17.1、根据结果嵌套

我们直接来看根据结果嵌套,看完这个懂了

17.2、根据查询嵌套

17.2.1、一对一

接口

@Select("select * from person")
@Results({@Result(column = "pid",property = "pid",id = true),@Result(column = "pname",property = "pname"),@Result(column = "ppassword",property = "ppassword"),@Result(column = "pid",property = "idnum",javaType = IDNum.class,one = @One(select = "club.winkto.mapper.PersonMapperAnno.selectIDNum",fetchType = FetchType.EAGER))
})
@Select("select * from idnum where pid=#{pid}")
IDNum selectIDNum(int pid);

测试

@Test
public void test3(){SqlSession sqlSession = MybatisUtil.getSqlSession();PersonMapperAnno mapper = sqlSession.getMapper(PersonMapperAnno.class);List<Person> people = mapper.selectPersonWithID();for (Person person : people) {System.out.println(person);}
}

17.2.2、一对多

接口

@Select("select * from person")
@Results({@Result(column = "pid",property = "pid",id = true),@Result(column = "pname",property = "pname"),@Result(column = "ppassword",property = "ppassword"),@Result(column = "pid",property = "orders",javaType = List.class,many = @Many(select = "club.winkto.mapper.PersonMapperAnno.selectOrder",fetchType = FetchType.EAGER))
})
List<Person> selectPersonWithOrder();
@Select("select * from orders where pid=#{pid}")
List<Order> selectOrder(int pid);

测试

@Test
public void test4(){SqlSession sqlSession = MybatisUtil.getSqlSession();PersonMapperAnno mapper = sqlSession.getMapper(PersonMapperAnno.class);List<Person> people = mapper.selectPersonWithOrder();for (Person person : people) {System.out.println(person);}
}

17.2.3、多对多

接口

@Select("select * from person")
@Results({@Result(column = "pid",property = "pid",id = true),@Result(column = "pname",property = "pname"),@Result(column = "ppassword",property = "ppassword"),@Result(column = "pid",property = "courses",javaType = List.class,many = @Many(select = "club.winkto.mapper.PersonMapperAnno.selectCourse",fetchType = FetchType.EAGER))
})
List<Person> selectPersonWithCourse();
@Select("select * from course,person_course where person_course.pid=#{pid} and person_course.cid=course.cid")
List<Course> selectCourse(int pid);

测试

@Test
public void test5(){SqlSession sqlSession = MybatisUtil.getSqlSession();PersonMapperAnno mapper = sqlSession.getMapper(PersonMapperAnno.class);List<Person> people = mapper.selectPersonWithCourse();for (Person person : people) {System.out.println(person);}
}

17.3、注解开启二级缓存

在接口上使用@CacheNamespace即可

17.4、注解开启延迟加载

  • fetchType = FetchType.LAZY
  • fetchType = FetchType.EAGER
  • fetchType = FetchType.DEFAULT(采用全局配置)

Java SSM篇3——Mybatis相关推荐

  1. Java SSM篇2——框架的基本认识

    Java SSM篇2--框架的基本认识 1.什么是框架 框架就是一套规范,既然是规范,你使用这个框架就要遵守这个框架所规定的约束 框架可以理解为半成品软件,框架做好以后,接下来在它基础上进行开发 2. ...

  2. Java SSM篇5——SpringMVC

    Java SSM篇5--SpringMVC 1.MVC模式 MVC是软件工程中的一种软件架构模式,它是一种分离业务逻辑与显示界面的开发思想 M(model)模型:处理业务逻辑,封装实体 V(view) ...

  3. Java+SSM(Spring+SpringMVC+Mybatis)个性化购物商城推荐系统 电子商务推荐系统 基于用户、项目、聚类、混合的协同过滤推荐算法WebShopRSMEx 源代码下载

    Java+SSM(Spring+SpringMVC+Mybatis)个性化购物商城推荐系统 电子商务推荐系统 基于用户.项目.聚类.混合的协同过滤推荐算法WebShopRSMEx 源代码下载 一.项目 ...

  4. 使用Java+SSM(Spring+SpringMVC+Mybatis)如何开发个性化音乐推荐系统 在线音乐推荐网站 基于用户、项目的协同过滤推荐算法实现MusicRecommendSystemWeb

    使用Java+SSM(Spring+SpringMVC+Mybatis)如何开发个性化音乐推荐系统 在线音乐推荐网站 基于用户.项目的协同过滤推荐算法实现MusicRecommendSystemWeb ...

  5. 如何使用Java+SSM(Spring+SpringMVC+Mybatis)开发个性化新闻推荐系统 在线新闻推荐系统 基于用户项目协同过滤、内容、聚类、关联规则推荐算法实现WebNewsRSMEx

    如何使用Java+SSM(Spring+SpringMVC+Mybatis)开发个性化新闻推荐系统 在线新闻推荐系统 基于用户项目协同过滤.内容.聚类.关联规则推荐算法实现WebNewsRSMEx 一 ...

  6. 使用Java+SSM(Spring+SpringMVC+Mybatis)开发在线美食推荐网 美食推荐系统 美食天下美食爬虫 基于用户、物品的协同过滤推荐算法实现 大数据、人工智能、机器学习项目开发

    使用Java+SSM(Spring+SpringMVC+Mybatis)开发在线美食推荐网 美食推荐系统 美食天下美食爬虫 基于用户.物品的协同过滤推荐算法实现 大数据.人工智能.机器学习项目开发Fo ...

  7. Java+SSM(Spring+SpringMVC+Mybatis)+Mysql个性化新闻推荐系统 基于用户、项目、内容、聚类、混合的协同过滤推荐算法WebNewsRSM 源代码下载

    Java+SSM(Spring+SpringMVC+Mybatis)+Mysql个性化新闻推荐系统 基于用户.项目.内容.聚类.混合的协同过滤推荐算法WebNewsRSM 源代码下载 一.项目简介 1 ...

  8. 使用Java+SSM(Spring+SpringMVC+Mybatis)如何开发个性化职位推荐系统 招聘推荐系统 基于用户、项目的协同过滤推荐算法实现WebPositionCFRS

    使用Java+SSM(Spring+SpringMVC+Mybatis)如何开发个性化职位推荐系统 招聘推荐系统 基于用户.项目的协同过滤推荐算法实现WebPositionCFRS 一.项目简介 1. ...

  9. Java SSM springmvc spring mybatis 集代码生成器 后台框架源码

    A代码编辑器,在线模版编辑,仿开发工具编辑器,pdf在线预览,文件转换编码 B 集成代码生成器 (单表.主表.明细表.树形表,快速开发利器)+快速表单构建器 freemaker模版技术 ,0个代码不用 ...

最新文章

  1. 清华大学公管学院、数据科学研究院共同助力国家数据治理,国家数据与治理联盟在京成立
  2. TypeError: __init__() takes 1 positional argument but 4 were given
  3. AC自动机 HDU 2222
  4. 【Java从0到架构师(1),Java中高级面试题总结(全面)
  5. 如何用ActionScript制作绚丽的特效——Silk
  6. SD从零开始16 促销计划(Agreements)
  7. linux脚本传参修改配置文件,shell脚本修改配置文件指定行的值
  8. 【离散数学笔记】计数原理:解决计数问题的基本方法
  9. Pannellum:实例之为全景图添加标题和作者
  10. 南阳理工ACM之房间安排
  11. 机器学习可以应用在哪些场景
  12. 蔡勒(Zeller)公式及其推导:快速将任意日期转换为星期数
  13. (Qt)windows下鼠标键盘热插拔监测
  14. chrome浏览器打开网页排版错乱
  15. enc易能变频_ENC易能变频器没反应快修诚信好
  16. 1-100之间的随机数小游戏
  17. pc端的微信dat文件解码转换成普通图片
  18. C++创建windows窗口
  19. 地图上如何量方位角_正距方位图是怎么画出来的?应该怎么看?有什么特点?...
  20. mysql 去除逗号_mysql注入之过滤逗号

热门文章

  1. [转载] python迭代器、生成器和装饰器
  2. [转载] Python中TFTP的理解
  3. 给定重量上限,背包问题_满足给定重量的袋子的最低成本
  4. math.asin_JavaScript中带有示例的Math.asin()方法
  5. 校园计算机网络系统,校园计算机网络系统
  6. python剑指offer面试题_剑指offer面试题Q10 斐波那契数列 python解法
  7. 计算机网络基础大学教材,《计算机网络技术及应用——大学计算机基础教育规划教材》低价购书_教材教辅考试_孔网...
  8. Java PushbackInputStream skip()方法与示例
  9. z字扫描和光栅扫描的转换_扫描转换计算机图形中的直线
  10. Spring官方推荐的@Transactional还能导致生产事故?