Java SSM篇3——Mybatis

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设置好的类型别名

别名类型
_bytebyte
_longlong
_shortshort
_intint
_integerint
_doubledouble
_floatfloat
_booleanboolean
stringString
byteByte
longLong
shortShort
intInteger
integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimalBigDecimal
bigdecimalBigDecimal
objectObject
mapMap
hashmapHashMap
listList
arraylistArrayList
collectionCollection
iteratorIterator

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(采用全局配置)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/557458.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在职研究生计算机科学与技术考研考哪些科目,计算机在职研究生考试科目

计算机在职研究生以三种方式来报考&#xff0c;分别是同等学力申硕、中外合作办学硕士、非全日制研究生。三种报考方式考试科目不同&#xff0c;下面为大家具体介绍一下。一、同等学力申硕考试科目&#xff1a;该方式考试科目主要有两科&#xff1a;外国语和学科综合。外国语&a…

Java SSM4——Spring

Java SSM4——Spring Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器&#xff08;框架&#xff09; Spring的优势 方便解耦&#xff0c;简化开发 Spring就是一个容器&#xff0c;可以将所有对象创建和关系维护交给Spring管理 什么是耦合度&#xff1f;对象之间的关…

计算机网络子网划分路由配置实验报告,完整的子网划分与路由交换实验报告 珍藏版哦...

洛阳理工学院实验报告系别班级学号姓名 课程名称 计算机网络实验日期实验名称 子网的划分路由器的配置 成绩实验目的&#xff1a;1&#xff1a;知道如何配置路由器信息 2&#xff1a;知道如何划分子网信息实验条件&#xff1a;电脑一台 packet tracer 运行环境【实验内容】在本…

html文件怎么导出stl文件,3D建模软件导出STL文件的小技巧(一)

很多用户在提交3D模型文件的时候&#xff0c;常常有这样的困惑&#xff1a;什么是STL 格式文件&#xff0c;怎么获取STL 格式文件呢&#xff1f;STL 格式文件是在计算机图形应用系统中&#xff0c;用于表示三角形网格的一种文件格式。它也是3D打印机在执行3D打印程序时&#xf…

Java SSM篇5——SpringMVC

Java SSM篇5——SpringMVC 1、MVC模式 MVC是软件工程中的一种软件架构模式&#xff0c;它是一种分离业务逻辑与显示界面的开发思想 M&#xff08;model&#xff09;模型&#xff1a;处理业务逻辑&#xff0c;封装实体V&#xff08;view&#xff09; 视图&#xff1a;展示内容…

空中最亮的星用计算机弹数字,赤峰——夜空中最亮的星_数字展示在线

8月25日&#xff0c;赤峰新区夜景照明改造升级PPP项目在新区管委会签约&#xff0c;这标志着全国首个城市夜景照明PPP项目正式落地。一切都从这一张照片开始在一个晴朗的夜晚摄影师拍下这张夜景之后赤峰便美得一发不可收拾这就是赤峰全国首个PPP夜景照明工程。项目一期包括八家…

Java SSM6——SSM整合

Java SSM6——SSM整合 1、Mybatis 1.1、数据库准备 CREATE TABLE person(id INT PRIMARY KEY,NAME VARCHAR(10),PASSWORD VARCHAR(10) ); INSERT INTO person VALUES (1,"root","123");1.2、创建maven工程&#xff0c;导入依赖 <dependencies>&l…

计算机基础知识掌握欠缺,浅谈计算机基础课程教学

浅谈计算机基础课程教学文章基于目前高职院校计算机基础课程的现状,重点对分(本文共2页)阅读全文>>本文主要通过对高职高专计算机课程的教学研究,提出教学中注重培养高素质,技能型人才的重...(本文共1页)阅读全文>>随着我国科技的快速发展,网络技术在各个行业领域都…

JAVA分布式篇1——Linux

JAVA分布式篇1——Linux 1、linux命令 1.1、常用指令 ls   显示文件或目录 -l 列出文件详细信息l(list)-a 列出当前目录下所有文件及目录&#xff0c;包括隐藏的a(all)mkdir 创建目录 -p 创建目录&#xff0c;若无父目录&#xff0c;则创建p…

计算机仿真在电力领域的应用,仿真技术在电力系统中的应用实例

自20世纪80年代末至今&#xff0c;我国的仿真技术获得了极大的发展。在电力系统中&#xff0c;应用较多的培训仿真系统有电厂仿真、电网运行工况仿真和变电所仿真。一般说来&#xff0c;凡是需要有一个或一组熟练人员进行操作、控制、管理与决策的实际系统&#xff0c;都需要对…

华中科技大学计算机学院考研大纲,2021华中科技大学考研大纲参考书目汇总

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼资料下载地址&#xff1a;http://fangcai.100xuexi.com/Ebook/DigitalLibrary/BookNew.aspx?BookName%u534E%u4E2D%u79D1%u6280%u5927%u5B66[视频]华中科技大学社会学院《437社会工作实务》[专业硕士]网授精讲班【大纲精讲】 [视频…

JAVA分布式篇2——Zookeeper

JAVA分布式篇2——Zookeeper 1、简介 Zookeeper是一个开源的分布式&#xff08;多台服务器干一件事&#xff09;的&#xff0c;为分布式应用提供协调服务的 Apache项目 2、工作机制 Zookeeper从设计模式角度来理解&#xff1a;是一个基于观察者模式&#xff08;一个人干活&a…

用计算机弹奏曲子童年,5.这首曲子使我想起了我的童年.十.书面表达现在.计算机游戏非常盛行.这是一件好事还是一件坏事?请你用英语写一篇短文来陈述自己的观点.并说明理由.字数:80-120....

5&#xff0e;这首曲子使我想起了我的童年.十.书面表达现在.计算机游戏非常盛行.这是一件好事还是一件坏事?请你用英语写一篇短文来陈述自己的观点.并说明理由.字数:80-120.【查看更多】题目列表(包括答案和解析)将下列英语句子译成汉语&#xff0c;汉语句子译成英语每空填写一…

JAVA分布式篇3——Dubbo

JAVA分布式篇3——Dubbo 1、架构演变 1.1、单应用架构 当网站流量很小时&#xff0c;只需要一个应用&#xff0c;将所有的功能部署到一起&#xff08;所有业务都放在一个tomcat 里&#xff09;&#xff0c;从而减少部署节点和成本用于简化 增删改查 工作量的数据访问框架 &a…

淮北市成人学计算机学校,安徽淮北市成人学电脑?

安徽淮北市成人学电脑&#xff1f;-"零基础"入学,签订就业协议,保证就业薪资,先就业后付款让你学习无忧就业无忧!成人学电脑 安徽成人学电脑 淮北市成人学电脑学电脑找高薪就业it专业就选择VR环境艺术创意设计师&#xff1a;专业优势&#xff0c;装饰行业需要人才时代…

Java分布式篇4——Redis

Java分布式篇4——Redis 1、互联网架构的演变历程 1.1、第一阶段 数据访问量不大&#xff0c;简单的架构即可搞定&#xff01; 1.2、第二阶段 数据访问量大&#xff0c;使用缓存技术来缓解数据库的压力不同的业务访问不同的数据库 1.3、第三阶段 主从读写分离。 之前的缓存…

计算机win7无法安装,新机装不了Win7?照这个方法5分钟搞定!

昨天有小伙伴在评论留言7代酷睿装不了Win7&#xff0c;评论回复有字数限制&#xff0c;小编今天就着重针对100/200系列主板安装Win7给大家推送一个教程&#xff0c;包括USB 3.0驱动和NVME驱动全部搞定&#xff0c;装Win7没有那难&#xff01;首先&#xff0c;下载Win7的原版镜像…

Java分布式篇5——FastDFS

Java分布式篇5——FastDFS 分布式文件系统 1、主流的分布式文件系统 1.1、 HDFS (Hadoop Distributed File System)Hadoop 分布式文件系统 高容错的系统&#xff0c;适合部署到廉价的机器上能提供高吞吐量的数据访问&#xff0c;非常适合大规模数据应用HDFS采用主从结构&a…

如何导出计算机硬盘重数据,硬盘对拷教程,100%保存原硬盘数据

硬盘对拷是老生常谈的问题&#xff0c;网上教程一搜一大把&#xff0c;这里也不是我原创了&#xff0c;就拷贝中关村的一篇写的比较详细的&#xff0c;普及下小白吧&#xff01;●Ghost硬盘对拷优点&#xff1a;全盘完全100%对拷&#xff0c;包括原有操作系统也可使用。新硬盘对…

计算机微格教学心得体会,微格教学心得体会6篇_微格教学体会报告

微格教学的英文为Microteaching&#xff0c;在我国被译为"微型教学"、"微观教学"、"小型教学"等&#xff0c;目前国内用得较多的是"微格教学"。微格教学是一种利用现代化教学技术手段来培训师范生和在职教师教学技能的系统方法。下面是…