0. 框架的基本概念

  • 三层架构

    • 界面层: 和用户打交道的, 接收用户的请求参数, 显示处理结果的。(jsp ,html ,servlet)
    • 业务逻辑层: 接收了界面层传递的数据,计算逻辑,调用数据库,获取数据
    • 数据访问层: 就是访问数据库, 执行对数据的查询,修改,删除等等的。
  • 三层对应的包

    • 界面层: controller包 (servlet
    • 业务逻辑层: service 包(XXXService类)
    • 数据访问层: dao包(XXXDao类)
  • 三层中类的交互
    用户使用界面层—> 业务逻辑层—->数据访问层(持久层)—>数据库(mysql)

  • 三层对应的处理框架

    • 界面层—-servlet—-springmvc(框架)
    • 业务逻辑层—-service类—spring(框架)
    • 数据访问层—-dao类—mybatis(框架)
  • 框架

框架是一个舞台, 一个模版

模版:

  1. 规定了好一些条款,内容。
  2. 加入自己的东西

框架是一个模块

  1. 1. 框架中定义好了一些功能。这些功能是可用的。
  2. 2. 可以加入项目中自己的功能, 这些功能可以利用框架中写好的功能。

框架是一个软件,半成品的软件,定义好了一些基础功能, 需要加入你的功能就是完整的。
基础功能是可重复使用的,可升级的。

框架特点:

  1. 框架一般不是全能的, 不能做所有事情
  2. 框架是针对某一个领域有效。 特长在某一个方面,比如mybatis做数据库操作强,但是他不能做其它的。
  3. 框架是一个软件

1. 基本概念

  • MyBatis 是一款优秀的持久层框架
  • 它支持定制化 SQL、存储过程以及高级映射。
  • MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
  • MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

总结:
mybatis是一个sql映射框架,提供的数据库的操作能力。增强的JDBC,
使用mybatis让开发人员集中精神写sql就可以了,不必关心Connection,Statement,ResultSet
的创建,销毁,sql的执行。

maven仓库:

  1. <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
  2. <dependency>
  3. <groupId>org.mybatis</groupId>
  4. <artifactId>mybatis</artifactId>
  5. <version>3.5.2</version>
  6. </dependency>

2. 基本应用

2.1 入门配置

Mybatis - 图1

2.1.1 配置数据库

  1. CREATE DATABASE `mybatis`;
  2. USE `mybatis`;
  3. CREATE TABLE `user`(
  4. `id` INT(20) NOT NULL PRIMARY KEY,
  5. `name` VARCHAR(30) DEFAULT NULL
  6. )DEFAULT CHARSET=utf8;
  7. INSERT INTO `user`(`id`,`name`) VALUES
  8. (10,'ahang'),
  9. (20,'haha'),
  10. (30,'kaka')
  11. +----+-------+
  12. | id | name |
  13. +----+-------+
  14. | 10 | ahang |
  15. | 20 | haha |
  16. | 30 | kaka |
  17. +----+-------+

2.1.2 在mavenpom.xml中导入依赖

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.mybatis</groupId>
  4. <artifactId>mybatis</artifactId>
  5. <version>3.5.7</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>mysql</groupId>
  9. <artifactId>mysql-connector-java</artifactId>
  10. <version>5.1.40</version>
  11. </dependency>
  12. <dependency>
  13. <groupId>junit</groupId>
  14. <artifactId>junit</artifactId>
  15. <version>4.13.2</version>
  16. </dependency>
  17. </dependencies>

并且配置好配置资源定位

  1. <!--在build中配置resources,来防止我们资源导出失败的问题-->
  2. <build>
  3. <resources>
  4. <resource>
  5. <directory>src/main/resources</directory>
  6. <includes>
  7. <include>**/*.properties</include>
  8. <include>**/*.xml</include>
  9. </includes>
  10. <filtering>true</filtering>
  11. </resource>
  12. <resource>
  13. <directory>src/main/java</directory>
  14. <includes>
  15. <include>**/*.properties</include>
  16. <include>**/*.xml</include>
  17. </includes>
  18. <filtering>true</filtering>
  19. </resource>
  20. </resources>
  21. </build>

2.1.3 配置User

在pojo包中定义一个User类,和数据库中user表对应

  1. package com.ahang.pojo;
  2. public class User {
  3. private int id;
  4. private String name;
  5. public User() {
  6. }
  7. public User(int id, String name){
  8. this.id = id;
  9. this.name = name;
  10. }
  11. }

2.1.4 增加接口UserDao.java

  1. package com.ahang.Dao;
  2. public interface UserDao {
  3. List<User> getUserList();
  4. }

2.1.5 数据库操作配置UserDaoImpl.xml

相当于将原来的UserDaoImpl.java改为了配置文件形式

UserDaoImpl.xml中配置对应的增删改查语句,获取user表的全部条目

注意点:此配置中存在中文注释可能会报错,不要添加中文注释在此

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.ahang.Dao.UserDao">
  6. <select id="getUserList" resultType="com.ahang.pojo.User">
  7. select * from Mybatis.user
  8. </select>
  9. </mapper>

2.1.6 配置mybatis的核心配置文件来连接数据库

mappers配置绑定不要忘记

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <!--configuration核心配置文件-->
  6. <configuration>
  7. <environments default="development">
  8. <environment id="development">
  9. <transactionManager type="JDBC"/>
  10. <dataSource type="POOLED">
  11. <property name="driver" value="com.mysql.jdbc.Driver"/>
  12. <property name="url" value="jdbc:mysql://localhost:3306/MyBatis"/>
  13. <property name="username" value="root"/>
  14. <property name="password" value="1598"/>
  15. </dataSource>
  16. </environment>
  17. </environments>
  18. <!--配置绑定不要忘记-->
  19. <mappers>
  20. <mapper resource="com/ahang/Dao/UserDaoImpl.xml"></mapper>
  21. </mappers>
  22. </configuration>

2.1.7 配置数据库工具类MybatisUtils

配置基本固定,只有mybatis.xml需要修改

  1. public class MybatisUtils {
  2. private static SqlSessionFactory sqlSessionFactory;
  3. static {
  4. try {
  5. String resource = "mybatis.xml";
  6. InputStream inputStream = Resources.getResourceAsStream(resource);
  7. sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  8. }catch (Exception e){
  9. e.printStackTrace();
  10. }
  11. }
  12. public static SqlSession getSqlSession(){
  13. return sqlSessionFactory.openSession();
  14. }
  15. }

可以通过设置事务自动提交,否则对于插入修改删除语句需要手动的使用commit()来完成

  1. public static SqlSession getSqlSession(){
  2. return sqlSessionFactory.openSession(true);
  3. }

2.1.8 测试类

  1. SqlSession sqlSession = MybatisUtils.getSqlSession();
  2. UserDao userDao = sqlSession.getMapper(UserDao.class);
  3. List<User> userList = userDao.getUserList();
  4. for(User e: userList){ System.out.println(e);}
  5. sqlSession.close();

2.2 错误排查

  • 错误code1:Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 7; columnNumber: 9; 1 字节的 UTF-8 序列的字节 1 无效
    Mybatis - 图2
    解决:删除中文注解或者注解中中文乱码错误详解
  • 错误CODE2org.apache.ibatis.binding.BindingException: Type interface com.ahang.Dao.UserDao is not known to the MapperRegistry

解决:在mybatis-config.xml配置文件中缺少<mappers> <mapper resource="com/ahang/Dao/UserDaoImpl.xml"></mapper> </mappers>注意路径通过\连接

  • 错误CODE3 数据库连接错误Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown database 'mybati'
    解决:查看数据库书写是否正确
  • 错误CODE4The error may exist in com/ahang/Dao/UserDaoImpl.xml; Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.io.IOException: Could not find resource com/ahang/Dao/UserDaoImpl.xml缺少资源包,在定义mavenpom.xml中默认没有添加资源包下的配置文件,需要手动添加Mybatis - 图3
  1. <build>
  2. <resources>
  3. <resource>
  4. <directory>src/main/resources</directory>
  5. <includes>
  6. <include>**/*.properties</include>
  7. <include>**/*.xml</include>
  8. </includes>
  9. <filtering>true</filtering>
  10. </resource>
  11. <resource>
  12. <directory>src/main/java</directory>
  13. <includes>
  14. <include>**/*.properties</include>
  15. <include>**/*.xml</include>
  16. </includes>
  17. <filtering>true</filtering>
  18. </resource>
  19. </resources>
  20. </build>

添加在pom.xml<project>

3. 增删改查

在数据库中创建一张表user如下

  1. +----+-------+
  2. | id | name |
  3. +----+-------+
  4. | 10 | ahang |
  5. | 20 | kaka |
  6. +----+-------+

定义一个User类,和数据库中user表对应

  1. package com.ahang.pojo;
  2. public class User {
  3. private int id;
  4. private String name;
  5. public User() {
  6. }
  7. public User(int id, String name){
  8. this.id = id;
  9. this.name = name;
  10. }
  11. ...setXXX...getXXX...
  12. }

增加接口UserDao.java

  1. public interface UserDao {
  2. List<User> getUserList();
  3. User getUserById(int id);
  4. int addUser(User user);
  5. int updateUser(User user);
  6. int deleteUser(int id);
  7. }

UserDaoImpl.xml中配置对应的增删改查语句

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.ahang.Dao.UserDao">
  6. <select id="getUserList" resultType="com.ahang.pojo.User">
  7. select * from Mybatis.user
  8. </select>
  9. <select id="getUserById" parameterType="int" resultType="com.ahang.pojo.User">
  10. select * from mybatis.user where id = #{id}
  11. </select>
  12. <insert id="addUser" parameterType="com.ahang.pojo.User">
  13. insert into mybatis.user values( #{id}, #{name} );
  14. </insert>
  15. <update id="updateUser" parameterType="com.ahang.pojo.User">
  16. update mybatis.user set name=#{name} where id=#{id};
  17. </update>
  18. <delete id="deleteUser" parameterType="int">
  19. delete from mybatis.user where id=#{id};
  20. </delete>
  21. </mapper>

最后测试结果在测试类中

  1. public class test {
  2. @Test
  3. public void test(){
  4. SqlSession sqlSession = MybatisUtils.getSqlSession();
  5. UserDao userDao = sqlSession.getMapper(UserDao.class);
  6. // 查询全部条目放在列表中
  7. List<User> userList = userDao.getUserList();
  8. for(User e: userList){
  9. System.out.println(e);
  10. }
  11. // 条件查询通过id
  12. User user = useDao.getUserById(20);
  13. System.out.println(user);
  14. // 增加一条用户信息,最后需要commit()才能生效
  15. int a = userDao.addUser(new User(40, "haha"));
  16. if(a > 0) System.out.println("insert sucessed");
  17. sqlSession.commit();
  18. // 更新用户信息
  19. int u = userDao.updateUser(new User(20, "kaka"));
  20. if(u > 0) System.out.println("update sucessed");
  21. sqlSession.commit();
  22. // 删除一条信息
  23. int d = mapper.deleteUser(30);
  24. if(d > 0) System.out.println("delete sucessed");
  25. sqlSession.commit();
  26. // 最后一定要关闭释放资源
  27. sqlSession.close();
  28. }
  29. }

4. mybatis.xml配置解析

4.1 标签顺序

标签的顺序—从上到下 :

properties

settings

typeAliases

typeHandlers

objectFactory

objectWrapperFactory

reflectorFactory

plugins

environments

databaseIdProvider

mappers

4.2 环境配置和属性配置

通过default设置当前使用的配置环境,可以配置多个环境,但是只能同时使用一个

可以引入外部的配置db.properties,当外部和内部配置的属性冲突时,优先使用外部配置的属性,如内部有username属性而外部没有则直接加入,内部和外部都有password属性时优先使用外部的

定义一个db.properties

  1. driver=com.mysql.jdbc.Driver
  2. url=jdbc:mysql://localhost:3306/mybatis
  3. password=6666

mybatis.xml中配置外部属性源和多个配置环境

  1. <properties resource="db.properties">
  2. <property name="username" value="root"></property>
  3. <property name="password" value="1111"></property>
  4. </properties>
  5. <!--通过default设置当前使用的配置环境,可以配置多个环境,但是只能同时使用一个-->
  6. <environments default="development">
  7. <environment id="development">
  8. <transactionManager type="JDBC"/>
  9. <dataSource type="POOLED">
  10. <property name="driver" value="${driver}"/>
  11. <property name="url" value="${url}"/>
  12. <property name="username" value="${username}"/>
  13. <property name="password" value="${password}"/>
  14. </dataSource>
  15. </environment>
  16. <environment id="test">
  17. <transactionManager type="JDBC"></transactionManager>
  18. <dataSource type="POOLED">
  19. <property name="driver" value="com.mysql.jdbc.Driver"/>
  20. <property name="url" value="jdbc:mysql://localhost:3306/MyBatis"/>
  21. <property name="username" value="root"/>
  22. <property name="password" value="1598"/>
  23. </dataSource>
  24. </environment>
  25. </environments>
  26. </environments>

4.3 类型别名(typeAliases)

方式一:
mybatis.xml中配置类型别名

  1. <typeAliases>
  2. <typeAlias type="com.ahang.pojo.User" alias="Users"></typeAlias>
  3. </typeAliases>

然后在UserDaoImpl.xml中使用该别名简化配置,避免多次使用较长的类名

  1. <select id="getUserList" resultType="com.ahang.pojo.User">
  2. select * from Mybatis.user
  3. </select>
  4. <select id="getUserList" resultType="Users">
  5. select * from Mybatis.user
  6. </select>

方式二:直接在定义类的时候添加别名注解

设置别名@Alias前添加包,此时会产生默认别名为小写的类名user,可以通过@Alias指定

  1. <!--可以给实体类起别名-->
  2. <typeAliases>
  3. <package name="com.kuang.pojo"/>
  4. </typeAliases>
  1. @Alias("users")
  2. public class User {
  3. private int id;
  4. private String name;
  5. }

4.4 映射绑定

每一个Mapper.xml都需要在mybatis.xml配置中绑定注册
方式一:手动指定位置

  1. <mappers>
  2. <mapper resource="com/ahang/Dao/UserDaoImpl.xml"></mapper>
  3. </mappers>

方式二:通过指定UserDao类自动寻找对应的UserDao.xml,需要配置文件和类同名

  1. <mappers>
  2. <mapper class="com.ahang.Dao.UserDao"></mapper>
  3. </mappers>

方式三:通过指定一个包,自动根据类名寻找对应的配置文件,需要配置文件和类同名

  1. <mappers>
  2. <package name="com.ahang.Dao"></package>
  3. </mappers>

5. 数据库属性名和类定义的属性名不同

数据库中使用了name,而对应结果类中属性定义了uname,两者不一致

  1. mysql> select * from user;
  2. +----+-------+
  3. | id | name |
  4. +----+-------+
  5. | 10 | ahang |
  6. | 20 | kaka |
  7. +----+-------+
  1. @Alias("users") // 设置别名,供后面mybatis.xml类名的使用
  2. public class User {
  3. private int id;
  4. private String uname;
  5. }

默认查出来的结果uname为空:

  1. User(id=10, uname=null)
  2. User(id=20, uname=null)

userDaoImpl.xml中配置

  1. <select id="getUserList" resultType="users">
  2. select * from mybatis.user;
  3. </select>

5.1 通过查询时设置别名

设置userDaoImpl.xml中查询语句,将原name返回结果设置为uname

  1. <select id="getUserList" resultType="users">
  2. select id,name as uname from mybatis.user;
  3. </select>

5.2 设置resultMap

设置resultMap来绑定属性名,property中属性为User类中, column中属性为数据库中值。

注意点:以下配置会报错:org.apache.ibatis.type.TypeException: Could not resolve type alias 'UserMap'. Cause: java.lang.ClassNotFoundException: Cannot find class: UserMap at org.apache.ibatis.builder.xml.XMLMapperBuilder.configurationElement

  1. <resultMap id="UserMap" type="users">
  2. <result property="id" column="id"></result>
  3. <result property="uname" column="name"></result>
  4. </resultMap>
  5. <select id="getUserList" resultType="UserMap">
  6. select * from mybatis.user;
  7. </select>
  • 首先需要添加resultMap绑定对应关系
  • 然后需要修改select标签中的resultType="users" —> resultMap="UserMap"
  • 正确配置如下:
  1. <resultMap id="UserMap" type="users">
  2. <!--相同属性名不需要修改,可以不写 <result property="id" column="id"></result>-->
  3. <result property="uname" column="name"></result>
  4. </resultMap>
  5. <select id="getUserList" resultMap="UserMap">
  6. select * from mybatis.user;
  7. </select>

6. 日志工厂

  • mybatis.xml中配置STDOUT_LOGGING
  1. <settings>
  2. <setting name="logImpl" value="STDOUT_LOGGING"/>
  3. </settings>
  • Log4j

    • Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件
    • 我们也可以控制每一条日志的输出格式;
    • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
    • 通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
    1. 先导包,在maven配置文件中

      1. <dependency>
      2. <groupId>log4j</groupId>
      3. <artifactId>log4j</artifactId>
      4. <version>1.2.17</version>
      5. </dependency>
    2. mybatis.xml中添加配置

      1. <settings>
      2. <setting name="logImpl" value="LOG4J"/>
      3. </settings>
    3. resourses资源包下添加log4j.properties配置

  1. #将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
  2. log4j.rootLogger=DEBUG,console,file
  3. #控制台输出的相关设置
  4. log4j.appender.console = org.apache.log4j.ConsoleAppender
  5. log4j.appender.console.Target = System.out
  6. log4j.appender.console.Threshold=DEBUG
  7. log4j.appender.console.layout = org.apache.log4j.PatternLayout
  8. log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
  9. #文件输出的相关设置
  10. log4j.appender.file = org.apache.log4j.RollingFileAppender
  11. log4j.appender.file.File=./log/ahng.log
  12. log4j.appender.file.MaxFileSize=10mb
  13. log4j.appender.file.Threshold=DEBUG
  14. log4j.appender.file.layout=org.apache.log4j.PatternLayout
  15. log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
  16. #日志输出级别
  17. log4j.logger.org.mybatis=DEBUG
  18. log4j.logger.java.sql=DEBUG
  19. log4j.logger.java.sql.Statement=DEBUG
  20. log4j.logger.java.sql.ResultSet=DEBUG
  21. log4j.logger.java.sql.PreparedStatement=DEBUG

7. 分页

主要使用select的limit语句select * from user limit 2, 3

SELECT * from user limit startIndex,pageSize;

  • 先在接口中添加
  1. public interface UserDao {
  2. List<User> getUserByLimit(Map<String,Integer> map);
  3. }
  • 然后在UserDao.xml接口对应配置文件中添加查询语句
  1. <select id="getUserByLimit" parameterType="map" resultMap="UserMap">
  2. select * from mybatis.user limit #{startIndex},#{pageSize}
  3. </select>
  • 最后测试,在里面添加对应的map
  1. @Test
  2. public void getUserByLimit(){
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. UserDao mapper = sqlSession.getMapper(UserDao.class);
  5. HashMap<String, Integer> map = new HashMap<String, Integer>();
  6. map.put("startIndex", 1);
  7. map.put("pageSize", 2);
  8. List<User> userList = mapper.getUserByLimit(map);
  9. for (User user : userList) {
  10. System.out.println(user);
  11. }
  12. sqlSession.close();
  13. }

或者通过MyBatis的分页插件PageHelper来实现

8. 注解开发

8.1 面向接口编程

  • 大家之前都学过面向对象编程,也学习过接口,但在真正的开发中,很多时候我们会选择面向接口编程
  • 根本原因 : 解耦 , 可拓展 , 提高复用 , 分层开发中 , 上层不用管具体的实现 , 大家都遵守共同的标准 , 使得开发变得容易 , 规范性更好
  • 在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了;
  • 而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程。

关于接口的理解

  • 接口从更深层次的理解,应是定义(规范,约束)与实现(名实分离的原则)的分离。
  • 接口的本身反映了系统设计人员对系统的抽象理解。
  • 接口应有两类:
  • 第一类是对一个个体的抽象,它可对应为一个抽象体(abstract class);
  • 第二类是对一个个体某一方面的抽象,即形成一个抽象面(interface);
  • 一个体有可能有多个抽象面。抽象体与抽象面是有区别的。

三个面向区别

  • 面向对象是指,我们考虑问题时,以对象为单位,考虑它的属性及方法 .
  • 面向过程是指,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现 .
  • 接口设计与非接口设计是针对复用技术而言的,与面向对象(过程)不是一个问题.更多的体现就是对系统整体的架构

MyBatis详细执行流程
Mybatis - 图4

8.2 使用注解开发与参数详解

@Select("select id, name as uname from user where id=#{id} and name=#{uname}")对于该语句来说,idname对应都是数据库里面的属性名,而uname是User类中属性名,一般两者相同

首先需要在mybatis.xml中绑定接口

  1. <!--绑定接口-->
  2. <mappers>
  3. <mapper class="com.ahang.Dao.UserDao"></mapper>
  4. </mappers>

注解只能对一些简单的语句使用,对于一些复杂的语句无法使用,如下第二条语句。

  1. public interface UserDao {
  2. @Select("select id, name as uname from user")
  3. List<User> getUserList();
  4. List<User> getUserByLimit(Map<String,Integer> map);
  5. // 对于单个参数时,可以指定@Param("参数别名"),也可以不写
  6. @Select("select id, name as uname from user where id=#{uid}")
  7. User getUserById(@Param("uid") int id);
  8. // 对于多个参数时,必须使用@Param("参数别名")来指定,否则报错
  9. @Select("select id, name as uname from user where id=#{id} and name=#{uname}")
  10. User getUserByUser(@Param("id") int id,@Param("uname") String uname);
  11. @Insert("insert into user values ( #{id}, #{uname} )")
  12. int addUser(User user);
  13. @Update("update user set name=#{uname} where id=#{id}")
  14. int updateUser(User user);
  15. @Delete("delete from user where id=#{id}")
  16. int deleteUser(int id);
  17. }
  • 一般都使用#{}来设置参数,MyBatis会创建 PreparedStatement 参数占位符,并通过占位符安全地设置参数(就像使用 ?一样)
  • ${}设置时,MyBatis 就不会修改或转义该字符串了,会直接替换存在安全性问题
  • 对于单个参数时,可以指定@Param("参数别名"),也可以不写
  • 对于多个参数时,必须使用@Param("参数别名")来指定,否则报错
  • 对于引用类型,不需要添加如:User user类型

9. Lombok

使用步骤:

  • 在IDEA中安装Lombok插件!
  • maven项目pom.xml中导入lombok的jar包
  1. <dependency>
  2. <groupId>org.projectlombok</groupId>
  3. <artifactId>lombok</artifactId>
  4. <version>1.18.10</version>
  5. </dependency>
  • 在实体类上加注解即可!
  1. @Data:无参构造,getsettostringhashcodeequals
  2. @AllArgsConstructor:有参构造
  3. @NoArgsConstructor:无参构造
  4. ...

10. 多对一

在数据库中添加studentteacher两个表

  1. CREATE TABLE `teacher` (
  2. `id` INT(10) NOT NULL,
  3. `name` VARCHAR(30) DEFAULT NULL,
  4. PRIMARY KEY (`id`)
  5. ) ENGINE=INNODB DEFAULT CHARSET=utf8;
  6. INSERT INTO teacher(`id`, `name`) VALUES (1, 'ahang');
  7. CREATE TABLE `student` (
  8. `id` INT(10) NOT NULL,
  9. `name` VARCHAR(30) DEFAULT NULL,
  10. `tid` INT(10) DEFAULT NULL,
  11. PRIMARY KEY (`id`),
  12. KEY `fktid` (`tid`),
  13. CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
  14. ) ENGINE=INNODB DEFAULT CHARSET=utf8;
  15. INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', 'aa', '1');
  16. INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', 'bb', '1');
  17. INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', 'cc', '1');
  18. INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', 'dd', '1');
  19. INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', 'ee', '1');

其中多个学生对应一个老师

  1. mysql> select * from teacher;
  2. +----+-------+
  3. | id | name |
  4. +----+-------+
  5. | 1 | ahang |
  6. +----+-------+
  7. 1 row in set (0.00 sec)
  8. mysql> select * from student;
  9. +----+----------+------+
  10. | id | name | tid |
  11. +----+----------+------+
  12. | 1 | haha | 1 |
  13. | 2 | hahaha | 1 |
  14. | 3 | hahahaha | 1 |
  15. | 4 | gaga | 1 |
  16. | 5 | gagaga | 1 |
  17. +----+----------+------+

需要查询获取每个学生对应的老师名称

首先在com.ahang.pojo包下建立学生Student和老师Teacher类:

  1. public class Student {
  2. private int id;
  3. private String name;
  4. private Teacher teacher; // Teacher类
  5. ...
  6. }
  7. public class Teacher {
  8. private int id;
  9. private String name;
  10. ...
  11. }

然后设置StuDao接口来获取Student的列表

  1. public interface StuDao {
  2. public List<Student> getStudent();
  3. }

我们在resourses的资源包下添加文件夹com.ahang.Daojava包下的com.ahang.Dao对应,然后在资源包下添加配置文件名为接口的类名StuDao.xml,后面绑定mybatis.xml配置文件时,会自动根据同一个包名自动匹配到配置文件

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.ahang.Dao.StuDao">
  6. <select id="getStudent" resultMap="StudentTeacher">
  7. select * from student;
  8. </select>
  9. <resultMap id="StudentTeacher" type="com.ahang.pojo.Student">
  10. <result property="id" column="id"></result>
  11. <result property="name" column="name"></result>
  12. <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"></association>
  13. </resultMap>
  14. <select id="getTeacher" resultType="Teacher">
  15. select * from Teacher where id=#{id};
  16. </select>
  17. </mapper>

mybatis.xml中添加绑定配置文件

  1. <mappers>
  2. <mapper class="com.ahang.Dao.StuDao"></mapper>
  3. </mappers>

最后测试结果

  1. @Test
  2. public void test(){
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. StuDao mapper = sqlSession.getMapper(StuDao.class);
  5. List<Student> student = mapper.getStudent();
  6. for (Student student1 : student) {
  7. System.out.println(student1);
  8. }
  9. }
  10. // Student(id=1, name=haha, teacher=Teacher(id=1, name=ahang))
  11. // Student(id=2, name=hahaha, teacher=Teacher(id=1, name=ahang))
  12. // Student(id=3, name=hahahaha, teacher=Teacher(id=1, name=ahang))
  13. // Student(id=4, name=gaga, teacher=Teacher(id=1, name=ahang))
  14. // Student(id=5, name=gagaga, teacher=Teacher(id=1, name=ahang))
  1. <select id="getStudent" resultMap="StudentTeacher">
  2. select s.id sid ,s.name sname, s.tid tid, t.name tname from student s,teacher t where s.tid=t.id;
  3. </select>
  4. <resultMap id="StudentTeacher" type="students">
  5. <result property="id" column="sid"></result>
  6. <result property="name" column="sname"></result>
  7. <!--对查出来的结果再做映射,获取想要的结果,通过association或collection-->
  8. <association property="teacher" javaType="Teacher">
  9. <result property="id" column="tid"></result>
  10. <result property="name" column="tname"></result>
  11. </association>
  12. </resultMap>

11. 一对多

12. 动态SQL

13. 缓存

13.1 什么是缓存 [ Cache ]?

存在内存中的临时数据。
将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。

  • 为什么使用缓存?

减少和数据库的交互次数,减少系统开销,提高系统效率。

  • 什么样的数据能使用缓存?

经常查询并且不经常改变的数据。【可以使用缓存】

13.2 Mybatis缓存

MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。

MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存

默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)

二级缓存需要手动开启和配置,他是基于namespace级别的缓存。

为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

Mybatis - 图5

13.3 一级缓存

一级缓存也叫本地缓存: SqlSession
与数据库同一次会话期间查询到的数据会放在本地缓存中。
以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库;
测试步骤:

  • 开启日志!
  • 测试在一个SqlSession中查询两次相同记录
  • 查看日志输出
  1. @Test
  2. public void test(){
  3. SqlSession sqlSession = MybatisUtils.getSqlSession();
  4. StuDao mapper = sqlSession.getMapper(StuDao.class);
  5. List<Student> student = mapper.getStudent();
  6. for (Student student1 : student) {
  7. System.out.println(student1);
  8. }
  9. // sqlSession.clearCache(); 手动清理缓存
  10. List<Student> student1 = mapper.getStudent();
  11. for(Student e: student1){
  12. System.out.println(e);
  13. }
  14. System.out.println(student == student1); // 显示true,表示存在本地缓存,没有另外从数据库中查询
  15. sqlSession.close();
  16. }

如果通过sqlSession.clearCache() 手动清理了缓存,那么第二次查询首先二级没有开启,然后一级缓存被清理了,那么就会通过数据库查询。两次查询获取结果的对象地址不同,则为false

13.4 二级缓存

  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存

  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存;

  • 工作机制

    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
    • 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
    • 新的会话查询信息,就可以从二级缓存中获取内容;
    • 不同的mapper查出的数据会放在自己对应的缓存(map)中;
  • 首先默认mybatis.xml中开启了缓存的,无需设置,也可以显现出来:
  1. <!--显示的开启全局缓存-->
  2. <setting name="cacheEnabled" value="true"/>
  • 然后通过在接口对应的配置中StuDao.xml中添加
  1. <cache readOnly="true"/>

这样就会对缓存只读,如果不添加readOnly=”true”的话,那么就会报错,需要在StudentTeacher类中添加实现接口public class Student implement Serializable来序列化对象

  • 最后测试
  1. @Test
  2. public void test(){
  3. // 定义两个SqlSession连接
  4. SqlSession sqlSession = MybatisUtils.getSqlSession();
  5. SqlSession sqlSession2 = MybatisUtils.getSqlSession();
  6. StuDao mapper = sqlSession.getMapper(StuDao.class);
  7. StuDao mapper2 = sqlSession2.getMapper(StuDao.class);
  8. // 此时对数据库查询了一次,会添加到二级缓存中
  9. List<Student> student = mapper.getStudent();
  10. for (Student student1 : student) {
  11. System.out.println(student1);
  12. }
  13. // 关闭第一个连接
  14. sqlSession.close();
  15. System.out.println("========================");
  16. // 第二个连接去去读取相同的数据,此时先找二级缓存,发现有直接取出
  17. List<Student> students2 = mapper2.getStudent();
  18. for(Student e: students2){
  19. System.out.println(e);
  20. }
  21. System.out.println("---------------------");
  22. // 开启二级缓存后,在同一个namespace下的用同一个缓存,则两个对象地址相同true
  23. System.out.println(student == students2);
  24. sqlSession2.close();
  25. }