Mybatis-9.28

环境:

  • JDK1.8

  • Mysql5.7

  • maven3.6.1

  • Idea

回顾:

  • JDBC
  • Mysql
  • Java基础
  • Maven
  • Junit

SSM框架:配置文件的。最好方式:看官网文档;

1、简介

1.1 什么是Mybatis

MyBatis 是一款优秀的持久层框架

MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。

MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

如何获得Mybatis?

  • Maven仓库
  • Github
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.7</version>
</dependency>

1.2 什么是持久化

数据持久化

  • 持久化就是将程序的数据在持久状态和瞬时状态转化的过程
  • 内存:断电即失
  • 数据库(JDBC),io文件持久化

为什么需要持久化?

  • 内存断点即失
  • 内存贵

1.3 持久层

Dao层 Service层 Controller层。。。。

  • 持久层 = 完成持久化工作的代码块

  • 层界十分明显

1.4 为什么需要Mybatis?

  • 传统的JDBC代码太复杂了。简化。框架。自动化。
  • 帮助程序员将数据存入到数据库中
  • 不用Mybatis也可以,更容易上手,使用的人多

后面 Spring SpringMVC SpringBoot

2、第一个Mybatis程序

思路:

搭建环境–>导入Mybatis–>编写代码–>测试

2.1 搭建环境

1. 搭建数据库

2. 新建项目

  • 新建普通Maven项目
  • 删除src目录,作为父项目
  • 父项目导入maven依赖
<!--    导入依赖-->
<dependencies><!--连接数据库--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.11</version></dependency><!-- mybatis --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.7</version></dependency><!--        单元测试--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><!--LOG4J依赖--><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency>
</dependencies>
  • 父项目手动配置资源过滤
<!--在build中配置resources,来防止我们资源导出失败的问题-->
<build><resources><resource><directory>src/main/resources</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource><resource><directory>src/main/java</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource></resources>
</build>

2.2 创建子模块

编写mybatis的核心配置文件 resources -> mybatis-config.xml

  • url 的值
  • 设置时区
  • useSSL = false
  • mysql 8.0 有问题 需要加入 allowPublicKeyRetrieval=true
  • 后来出现了一个问题,就是property name属性里的值是固定的
<?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><!--    配置多个环境--><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&amp;useSSL=false&amp;useUnicode=true&amp;characterEncoding=utf-8&amp;allowPublicKeyRetrieval=true"/><property name="username" value="root"/><property name="password" value="root"/></dataSource></environment></environments><!--    每一个Mapper.xml都需要在Mybatis核心配置    文件中注册!--><mappers><mapper resource="com/wjs/dao/UserMapper.xml"/></mappers>
</configuration>

编写mybatis工具类

SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。

SqlSession 就类似于JDBC 里的 PrepareStatement ,用来执行的

package com.wjs.utils;
/*** SqlSessionFactory ---> sqlSession*/
public class mybatisUtils {private static SqlSessionFactory sqlSessionFactory;/***  第一步*  获取sqlSessionFactory对象*/static {try {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);} catch (IOException e) {e.printStackTrace();}}/*** 第二步* 既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。*/public static SqlSession getSqlSession(){return sqlSessionFactory.openSession();}
}

2.3 编写代码

  • 实体类
package com.wjs.pojo;public class User02 {private int id;private String name;private String pwd;public User02() {}public User02(int id, String name, String pwd) {this.id = id;this.name = name;this.pwd = pwd;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPwd() {return pwd;}public void setPwd(String pwd) {this.pwd = pwd;}
}
  • Dao接口
public interface UserDao {public List<User> getUserList();
}
  • Dao接口实现类 由原来的UserDaoImpl转变为一个Mapper配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace 绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.wjs.dao.UserDao">
<!--    select查询语句--><select id="getUserList" resultType="com.wjs.pojo.User">select * from user;</select>
</mapper>

2.4 测试

注意点junit测试 test文件夹下

@Test
public void test(){//第一步 获取sqlSessionSqlSession sqlSession = MybatisUtils.getSqlSession();//第二步 执行SQLUserDao mapper = sqlSession.getMapper(UserDao.class);List<User> userList = mapper.getUserList();for (User user : userList) {System.out.println(user);}//关闭sqlSessionsqlSession.close();
}

1.第一个可能错误 没有给Mapper.xml注册

  • org.apache.ibatis.binding.BindingException: Type interface com.wjs.dao.UserDao is not known to the MapperRegistry.

MapperRegistry是什么?

2. 第二个可能错误 约定大于配置 java文件夹里只有class文件能被过滤 手动配置资源过滤

  • java.lang.ExceptionInInitializerError
  • Error building SqlSession.
  • The error may exist in com/wjs/dao/UserMapper.xml
    <!--在build中配置resources,来防止我们资源导出失败的问题--><build><resources><resource><directory>src/main/resources</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource><resource><directory>src/main/java</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource></resources></build>

3. 也是文件过滤问题

  • mybatis错误——java.io.IOException: Could not find resource mybatis-config.xml
  • src/main/resources 目录下的是includes 而不是excludes,因为我在外面的test文件夹下执行

找不到mybatis-config.xml的,查看一下pom.xml中你那个内部标签是 include而不是exclude!!!(原因在于你之前在某些地方直接粘的,但是他写错了)

4.接口绑定错误

5.方法名不对

2.5总结

  • SqlSessionFactoryBuilder :一旦创建了 SqlSessionFactory,就不再需要它了。
  • SqlSessionFactory: 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
  • SqlSession:SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。 try catch finally

3、CRUD

出现了小问题:

  • MySQL 8.0 Public Key Retrieval is not allowed 错误的解决方法
  • 最简单的解决方法是在连接后面添加 allowPublicKeyRetrieval=true

3.1 namespace

namespace 中的包名要和Dao/Mapper接口的包名一致!

3.2 select:选择查询语句

  • id: 就是对应的 namespace 中的方法名
  • resultType: Sql语句执行的返回值 (Class / int)
  • parameterType:参数类型

3.3 补充:尽量不要使用自动提交(安全)

在MybatisUtils中的获取SqlSession方法中加入一个参数,可以设置成为自动提交

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

3.3 增删查改

  • 基本都类似,但得注意
  • mybatis框架自动帮你开启事务,你得手动结束事务

第一步: 编写接口

package com.wjs.dao;public interface UserMapper {//查询全部用户public List<User> getUserList();//根据id查询用户public User getUserById(int id);//添加用户public int addUser(User user);//修改用户public int updateUser(int id);//删除一个用户int deleteUser(int id);
}

第二步:编写mapper

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace 绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.wjs.dao.UserMapper">
<!--    select查询语句-->
<!--    查询全部用户--><select id="getUserList" resultType="com.wjs.pojo.User">select * from mybatis.user</select><!--    查询id用户--><select id="getUserById" resultType="com.wjs.pojo.User" parameterType="int">select * from user where id = #{id}</select><!--    添加用户  对象中的属性可以直接取出来--><insert id="addUser" parameterType="com.wjs.pojo.User">insert into user(id, name ,pwd) value (#{id},#{name},#{pwd});</insert><!--    修改用户 --><update id="updateUser" parameterType="int">update user set name = "龙龙" where id = #{id}</update><!--    删除用户--><delete id="deleteUser" parameterType="int">delete from user where id = #{id};</delete>
</mapper>

第三步: 编写代码

    public void testPrint(int updaterows){if(updaterows > 0 ){System.out.println("success...");test01();}else System.out.println("error...");}@Test//查询全部用户public void test01(){//第一步 获取sqlSessionSqlSession sqlSession = MybatisUtils.getSqlSession();//第二步 执行SQLUserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> userList = mapper.getUserList();for (User user : userList) {System.out.println(user);}//关闭sqlSessionsqlSession.close();}@Test//id来查询用户public void test02(){//第一步 获取sqlSessionSqlSession sqlSession = MybatisUtils.getSqlSession();//第二步 执行SQLUserMapper mapper = sqlSession.getMapper(UserMapper.class);//UserMapper.class接口的类对象实例化User user = mapper.getUserById(2);System.out.println(user);//关闭sqlSessionsqlSession.close();}@Test//添加用户 需要提交事务public void test03(){//第一步 获取sqlSessionSqlSession sqlSession = MybatisUtils.getSqlSession();//第二步 执行SQLUserMapper mapper = sqlSession.getMapper(UserMapper.class);//UserMapper.class接口的类对象实例化int updaterows = mapper.addUser(new User(5,"xiaolaodi","1234567"));//第三步 提交事务  mybatis默认开启事务,所以需要在这里关闭事务sqlSession.commit();testPrint(updaterows);//关闭sqlSessionsqlSession.close();}@Test//修改用户 需要提交事务public void test04(){//第一步 获取sqlSessionSqlSession sqlSession = MybatisUtils.getSqlSession();//第二步 执行SQLUserMapper mapper = sqlSession.getMapper(UserMapper.class);//UserMapper.class接口的类对象实例化int updaterows = mapper.updateUser(4);//第三步 提交事务  mybatis默认开启事务,所以需要在这里关闭事务sqlSession.commit();testPrint(updaterows);//关闭sqlSessionsqlSession.close();}@Test//删除用户 需要提交事务public void test05(){//第一步 获取sqlSessionSqlSession sqlSession = MybatisUtils.getSqlSession();//第二步 执行SQLUserMapper mapper = sqlSession.getMapper(UserMapper.class);//UserMapper.class接口的类对象实例化int updaterows = mapper.updateUser(5);testPrint(updaterows);//第三步 提交事务  mybatis默认开启事务,所以需要在这里关闭事务sqlSession.commit();//关闭sqlSessionsqlSession.close();}

3.4 分析错误: 读错从后往前读

  • xml 中 中文注释可能乱码 可以解决
  • CRUD标签不要匹配错
  • mybatis-config.xml(resources)中配置mapper,路径使用 /
  • NullPointException , 没有注册到资源!
  • Maven资源没有导出问题

3.5 万能的Map(重点)

//添加用户_万能map
int addUser02(Map<String,Object> map);
<!--    添加用户_万能map-->
<insert id="addUser02" parameterType="map">insert into user(id,name,pwd) values (#{userId},#{userName},#{userPwd})
</insert>
@Test//添加用户map方法 需要提交事务re
public void test06(){//第一步 获取sqlSessionSqlSession sqlSession = MybatisUtils.getSqlSession();//第二步 执行SQLUserMapper mapper = sqlSession.getMapper(UserMapper.class);//UserMapper.class接口的类对象实例化Map<String ,Object> map = new HashMap<String, Object>();map.put("userId",4);map.put("userName","龙龙");map.put("userPwd","1234");int updaterows = mapper.addUser02(map);//第三步 提交事务  mybatis默认开启事务,所以需要在这里关闭事务sqlSession.commit();testPrint(updaterows);//关闭sqlSessionsqlSession.close();
}
  • Map传递参数,直接在sql中取出key即可! paramemterType = “map”
  • 对象传递参数,直接在sql中取出对象即可 paramemterType = “object”
  • 只有一个基本类型参数的情况下,可以直接在sql中取得
  • 多个参数用Map,或者注解!

3.6 模糊查询 like

用 #{} 防止SQL注入问题

1.java代码执行的时候,传入通配符 % %

List<User> userList = mapper.getUserList("%李%");

2.在sql拼接中使用通配符 (两种都可以,这种有sql注入问题)

select * from user where id = "%"#{value}"%"

4、配置解析

在xml中,所有的标签都要按照规定的顺序

4.1 核心配置文件 :mybatis-config.xml

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:

  • properties 属性
  • settings 设置
  • typeAliases 类型别名
  • environments 环境配置
  • mappers 映射器
  • 其他的不重要

4.2 环境配置 environments

mybatis 可以适应多个环境,但每个SqlSessionFactory 实例只能选择一种环境

学会使用配置多套运行环境!

  • Mybatis默认的事务管理器(transactionManager) 是JDBC

  • 默认的连接池(dataSource) 是 POOLED

4.3 属性是环境配置里的重点

1.可以在外部进行配置 【resources/ db.properties】(推荐)

**& amp; 要改为 & **

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true
username=root
password=root

在核心配置文件中引入 优先使用外部配置文件!

<!--    引入外部配置文件-->
<properties resource="db.properties"></properties>

4.4 类型别名(TypeAliases)

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。

1. 可以在配置中手动添加

<typeAliases><typeAlias alias="Author" type="domain.blog.Author"/><typeAlias alias="Blog" type="domain.blog.Blog"/><typeAlias alias="Comment" type="domain.blog.Comment"/><typeAlias alias="Post" type="domain.blog.Post"/><typeAlias alias="Section" type="domain.blog.Section"/><typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>

2. 可以扫描实体类 (推荐)

例如pojo下有个实体类User

那么默认 < typeAlias alias=“user” type=“com.wjs.pojo.User” / >

<typeAliases><package name="com.wjs.pojo"/>
</typeAliases>

3. 通过注解 实体类 ,可以直接使用

@Alias("user")
public class User{}

4.5 设置(Settings)

  • logimpl
  • cacheEnabled
  • lazyLoadingEnabled

4.6 其他配置(初学没有任何作用)

  • plugins插件

    • mybatis-generator-core
    • mybatis-plus
    • 通用mapper

4.7 映射器(mappers)重点

MapperRegistry: 注册绑定外面的Mapper文件:

<!--    每一个Mapper.xml都需要在Mybatis核心配置    文件中注册!-->
<mappers><mapper resource="com/wjs/dao/UserMapper.xml"/>
</mappers>
<!--    每一个Mapper.xml都需要在Mybatis核心配置    文件中注册!-->
<mappers><mapper class="com.wjs.dao.UserMapper.xml"/>
</mappers>

区别

  • mapper标签,通过resource属性引入classpath路径的相对资源

  • **mapper标签,通过class属性指定mapper接口名称,此时对应的映射文件必须与接口位于同一路径下,并且名称相同 **

  • 放入java.com.wjs.dao 和放入 resources.com.wjs.dao 最终在classes中是同已路径

4.8 作用域(Scope)和生命周期

错误的使用会导致非常严重的并发问题

SqlSessionFactoryBuilder:

  • 一旦创建SqlSessionFactory,就不再需要它了
  • 局部变量

SqlSessionFactory:

  • 说白了就是可以想象成:数据库连接池
  • 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。

SqlSession:

  • 每个线程都应该有它自己的 SqlSession 实例。
  • 连接到连接池的一个请求
  • 返回一个响应后,就关闭它,否则资源被占用!

举个栗子:

  • SqlSessionFactoryBuilder 造车工厂
  • SqlSessionFactory 租车公司
  • SqlSession用户
  • 用户用完车得归还车

5、解决属性名和字段名不一致的问题

5.1 问题:

当pojo中的实体类的字段名和mysql中的字段名不想同时,如何解决问题?

5.2 解决方法:

  • Sql 中的 as 取别名

  • resultMap

5.3resultMap(结果集映射) 改名

  • resultMap 元素是 MyBatis 中最重要最强大的元素。

  • ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。

  • resultType=“user” 变成 resultMap=“UserMap”

  • column 表示数据库字段

  • property表示实体类的属性

  • 原理就是hashmap,但mybatis有resultMap支持

  • 什么不一样转什么,如果column和property一样,则不需要写

<resultMap id="UserMap" type="user">
<!--<result column="id" property="id"/>-->
<!--<result column="name" property="name"/>--><result column="pwd" property="pwd"/>
</resultMap><!--    查询id用户-->
<select id="getUserById" resultMap="UserMap" parameterType="int" >select * from user where id = #{id}
</select>
  • 10 11 讲了关于一对多( collection) 和 多对一 (association)

6、日志

6.1 日志工厂

如果一个数据库操作出现了异常,需要排错。日志就是最好的助手!

曾经:sout,debug

现在:日志工厂

6.2 logImpl:

在核心配置文件中配置settings

指定 MyBatis 所用日志的具体实现,未指定时将自动查找。

  • SLF4J

  • LOG4J(掌握)

  • LOG4J2

  • JDK_LOGGING

  • COMMONS_LOGGING

  • STDOUT_LOGGING (掌握)

  • NO_LOGGING

    出错可能

  • 未导包

  • 大小写,多个空格

  • 代码错了

在Mybatis中具体使用哪一个日志实现,在设置中设定!

6.3 STDOUT_LOGGING 标准输出日志

<settings><setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
Opening JDBC Connection
Created connection 1632413663.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@614ca7df]
==>  Preparing: select * from user where id = ?
==> Parameters: 2(Integer)
<==    Columns: id, name, pwd
<==        Row: 2, 金文强, 123456
<==      Total: 1
User{id=2, name='金文强', pwd='123456'}
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@614ca7df]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@614ca7df]
Returned connection 1632413663 to pool.

6.4 LOG4J

1. 什么是LOG4J?

  • 通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件

  • 我们也可以控制每一条日志的输出格式

  • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。

  • 这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

2. 导入LOG4J的包

<!--LOG4J依赖-->
<dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version>
</dependency>

3. 在resources 中建立 log4j.properties 内容如下:

  • log4j.appender.file.File=./log/wjs.log 文件配置地址
#将等级为DEBUG的日志信息输出到console和file两个目的地
log4j.rootLogger=DEBUG,console,file#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/wjs.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

4.核心配置文件中 设置settings

<settings><setting name="logImpl" value="LOG4J"/>
</settings>

5. 简单实用

  • 1.在要使用Log4j的类中,导入包 import org.apache.log4j.Logger;
  • 2.日志对象,参数为当前类的class
  • 要求会使用日志

7、分页

7.1 使用 limit 分页

  • Mybatis 框架真的太简便了

  • 多用万能map,虽然不规范,但很实用!

//分页
public List<User> getUserByLimit(Map<String,Object> map);
<!--    分页-->
<select id="getUserByLimit" resultType="user" parameterType="map">select * from user limit #{startIndex},#{pageSize}
</select>
@Test//分页
public void test03(){SqlSession sqlSession = MybatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);Map<String, Object> map = new HashMap<String, Object>();map.put("startIndex",1);map.put("pageSize",2);List<User> userByLimit = mapper.getUserByLimit(map);for (User user : userByLimit) {System.out.println(user);}sqlSession.close();
}

7.2 RowBounds分页(不建议)

7.3 分页插件(PageHelper)(简单,慢,配置多)

8、使用注解开发(Mybatis不推荐)

底层主要运用反射(反射复习)

反射是框架的灵魂

Mybatis一般使用配置(xml)开发

其他一般都是用注解开发

8.1 面向接口编程:解耦

8.2 CRUD

  • 再提醒遍,最好取消自动提交,安全
  • 参数是User时,前面添加@Param(“User”)会导致问题,看8.3
//方法存在多个参数,所有的参数前面必须加上 @Param("")注解
//注解 根据id查询用户
@Select("select * from user where id = #{id}")
public User getUserById02(@Param("id") int id);//增加
@Insert("insert into user(id,name,pwd) values(#{id},#{name},#{pwd})")
public int insertUser02(User user);//修改
@Update("update user set name = #{name} where id =  #{id}")
public int updateUser02(@Param("name") String name , @Param("id") int id);//删除
@Delete("delete from user where id = #{id}")
public int deleteUser02(int id);

8.3 关于@Param() 注解

  • 基本类型的参数或者String类型需要加上
  • 引用类型不需要加
  • 如果只有一个基本类型,可以省略@Param()注解
  • #{} 预编译 能防止sql注入
  • ¥{} 编译 无法防止sql注入

9、Lombok(第三方工具,极其方便)

插件 自动生成实体类的信息(有争议)

9.1 在Ieda中安装Lombok插件

  • 1.在设置中找到插件,搜索 lombok
  • 2.如果idea中搜索不到任何插件,那么点击当前界面右上角设置, 进入http sroxy setting,勾选auto-detect proxy seting

9.2 导入依赖

<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.20</version><scope>provided</scope>
</dependency>

9.3 @Data

  • 无参构造
  • get
  • set
  • toString
  • hashcode
  • equals
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Data  //get set tostring
@AllArgsConstructor //全部参数构造器
@NoArgsConstructor //无参构造器
public class User {private int id;private String name;private String pwd;
}

9.4 缺点

  • 按需的方法需要重写

10、多对一处理(重点)

多对一:关联

一对多:集合

10.1 环境搭建

1 建立数据库

CREATE TABLE `teacher`(
`id` INT NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8INSERT INTO teacher(`id`,`name`)VALUES (1,秦老师);CREATE TABLE `student`(
`id` INT NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT DEFAULT NULL,
PRIMARY KEY(`id`),
KEY `fktid`(`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
DROP TABLE studentINSERT INTO `student`(`id`,`name`,`tid`) VALUES(1,小明,1);
INSERT INTO `student`(`id`,`name`,`tid`) VALUES(2,小红,1);
INSERT INTO `student`(`id`,`name`,`tid`) VALUES(3,小张,1);
INSERT INTO `student`(`id`,`name`,`tid`) VALUES(4,小李,1);
INSERT INTO `student`(`id`,`name`,`tid`) VALUES(5,小王,1)

2 导入lombok 建立实体类 Teacher,Student

3 建立java.wjs.dao.Mapper接口

4 建立resources.com.wjs.dao.Mapper.xml文件

5 在核心配置文件中绑定注册Mapper接口或者文件

6 测试

10.2 查询所有的学生信息,以及对应的老师的信息!

10.3 按照查询嵌套处理: sql中的子查询思路

  • 在getStudent中嵌套查询老师的方法
  • association来给teacher类对象赋值
<mapper namespace="com.wjs.dao.StudentMapper"><!--1. 查询所有的学生信息2. 根据查询出来的学生的tid,寻找对应的老师子查询--><select id="getStudent" resultMap="StuTeaMap">select * from student</select><resultMap id="StuTeaMap" type="student"><result property="id" column="id"/><result property="name" column="name"/><!--复杂的属性我们需要单独处理对象 association集合 collection--><association property="teacher" column="tid" javaType="teacher" select="getTeacher"/></resultMap><select id="getTeacher" resultType="teacher" parameterType="int">select * from teacher where id = #{id};</select></mapper>
    public Teacher getTeacher(int id);//    //查询所有的学生信息,以及对应的老师的信息!public List<Student> getStudent();

10.4 按照结果嵌套处理(这种简单方便) 联表查询思路

<mapper namespace="com.wjs.dao.StudentMapper"><select id="getStudent" resultMap="StuTeaMap">select s.id sid,s.name sname,t.name tname from student s,teacher t where s.tid = t.id</select><resultMap id="StuTeaMap" type="Student"><result property="id" column="id"/><result property="name" column="sname"/><association property="teacher" javaType="Teacher"><result property="name" column="tname"/></association></resultMap></mapper>

11、一对多处理

比如: 一个老师有多个学生

11.1 查询指定老师下的所有学生及老师的信息

11.2 按结果嵌套处理 联表思路

  • 因为集合类型,javaType无法写,因此设置ofType为Student
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Teacher {private int id;private String name;private List<Student> students;
}
<mapper namespace="com.wjs.dao.TeacherMapper"><!--    select查询语句--><select id="getTeacher" resultMap="TecStuMap" parameterType="int">select s.id sid,s.name sname, s.tid tid,t.id tid,t.name tnamefrom student s,teacher twhere s.tid = t.id and t.id = #{tid}</select><!--javaType 指定属性的类型集合中的泛型信息,我们使用ofType获取--><resultMap id="TecStuMap" type="Teacher"><result property="id" column="tid"/><result property="name" column="tname"/><collection property="students" ofType="Student"><result property="id" column="sid"/><result property="name" column="sname"/><result property="tid" column="tid"/></collection></resultMap></mapper>

11.3 查询嵌套(子查询)

麻烦就不写了

11.4 小结

  • 关联 association 多对一
  • 集合 collection 一对多
  • javaType 指定实体类中的属性
  • ofType 用来指定映射到List或者集合中的pojo类型,泛型中的约束泛型!

注意点

  • 保证sql的可读性
  • 注意一对多 和 多对一 中,属性名和字段问题
  • 如果问题不好排查,建议使用log4j

12、动态SQL(重点)

12.1 什么是动态SQL

动态SQL就是根据不同的条件生成不同的SQL语句(以前手动拼接)

例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

12.2 基本元素

如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

12.3 搭建环境

  • 编写实体类
  • Mapper接口 xml
CREATE TABLE `blog`(
`id` VARCHAR(50) NOT NULL COMMENT 博客id,
`title` VARCHAR(100) NOT NULL COMMENT 博客标题,
`author` VARCHAR(30) NOT NULL COMMENT 博客作者,
`create_time` DATETIME NOT NULL COMMENT 创建时间,
`views` INT(30) NOT NULL COMMENT 浏览量
)ENGINE=INNODB DEFAULT CHARSET=utf8

12.4 解决属性名字段名不一致:mapUnderscoreToCamelCase

mapUnderscoreToCamelCase(true/false):是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。

<settings><setting name="logImpl" value="LOG4J"/><!--            开启字段名与属性名不一致,下划线转驼峰命名--><setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

12.5 UUID生成随机ID(实用)

public class IDutils {public static String getId(){return UUID.randomUUID().toString().replaceAll("-","");}@Testpublic void test(){System.out.println(IDutils.getId());System.out.println(IDutils.getId());}}

12.6 添加数据

//插入数据
public int addBlog(Blog blog);
<insert id="addBlog" parameterType="blog">insert into blog(id,title,author,create_time,views)values (#{id},#{title},#{author},#{createTime},#{views})
</insert>
@Test
public void test01(){SqlSession sqlSession = MybatisUtils.getSqlSession();BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);int i = mapper.addBlog(new Blog(IDutils.getId(), "数据库", "wjs", new Date(), 30));//事务提交sqlSession.commit();if(i>0) System.out.println("insert success...");sqlSession.close();
}

12.7 IF 语句

  • if里面的test属性是判断的语句
//查询博客
List<Blog> queryBlogIF(Map map);
<select id="queryBlogIF" parameterType="map" resultType="Blog">select * from blog where 1=1<if test="title != null">and title = #{title}</if>
</select>
@Test
public void test02(){SqlSession sqlSession = MybatisUtils.getSqlSession();BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);HashMap map = new HashMap();map.put("title","操作系统");List<Blog> blogs = mapper.queryBlogIF(map);for (Blog blog : blogs) {System.out.println(blog);}sqlSession.close();
}

12.8 choose , when , otherwise 语句 & where标签

<select id="findActiveBlogLike"resultType="Blog">SELECT * FROM BLOG WHERE state = ‘ACTIVE’<choose><when test="title != null">AND title like #{title}</when><when test="author != null and author.name != null">AND author_name like #{author.name}</when><otherwise>AND featured = 1</otherwise></choose>
</select>

where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。(就是不用写1=1,用where标签代替,解决不安全的问题)

<select id="findActiveBlogLike"resultType="Blog">SELECT * FROM BLOG<where><if test="state != null">state = #{state}</if><if test="title != null">AND title like #{title}</if><if test="author != null and author.name != null">AND author_name like #{author.name}</if></where>
</select>

这个例子中,set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。与where用法类似,智能

<update id="updateAuthorIfNecessary">update Author<set><if test="username != null">username=#{username},</if><if test="password != null">password=#{password},</if><if test="email != null">email=#{email},</if><if test="bio != null">bio=#{bio}</if></set>where id=#{id}
</update>

prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。(很少用)

<trim prefix="WHERE" prefixOverrides="AND |OR ">...
</trim>

所谓的动态sql本质还是sql语句,只是我们可以在sql层面去执行一些逻辑代码

12.9 SQL片段(可读性差,不推荐)

有时候,我们可能会将一些重复片段提取出来

注意事项

  • sql片段最好简单

12.10 Foreach (不常用,但需要会使用)

动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)

  • open="(" separator="," close=")" 开头添加 ( ,结尾添加 ) 用 , 来分割
<select id="selectPostIn" resultType="domain.blog.Post">SELECT *FROM POST PWHERE ID in<foreach item="item" index="index" collection="list"open="(" separator="," close=")">#{item}</foreach>
</select>

建议:

  • 现在mysql中写出完整的sql
  • 在对应的修改成为动态sql,实现通用

12.11 Mysql复习重点

  • Mysql引擎
  • InnoDB底层原理
  • 索引
  • 索引优化

13、缓存(reids,一般不会再Mybatis中使用)

13.1 简介

  1. 什么是缓存【Cache】?

    • 存在内存中的临时数据
    • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存查询,从而提高查询效率,解决了高并发系统的性能问题。
  2. 为什么使用缓存?
    • 减少和数据库交互的次数,减少系统开销,提高系统效率
  3. 什么样的数据能使用缓存?
    • 经常查询并且不经常改变的数据。

13.2 Mybatis缓存

  • Mybatis包含一个非常强大的查询缓存特性,它可以非常方便的定制和配置缓存。缓存可以极大的提升查询效率。
  • Mybatis系统中默认定义了两级缓存:一级缓存二级缓存
    • 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)
    • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存
    • 为了提高扩展性,Mybatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

13.3 一级缓存(没啥用)

  • 一级缓存也叫本地缓存:SqlSession

    • 与数据库同一次会话期间查询到的数据会放在本地缓存中
    • 以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库

测试步骤:

  1. 开启日志
  2. 测试再一次Session中查询两次相同记录
@Test
public void test01(){SqlSession sqlSession = MybatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user = mapper.queryUser(1);System.out.println(user);User user2 = mapper.queryUser(1);System.out.println(user2);sqlSession.close();
}
  1. 观察日志发现sql只查询了一次

  2. 缓存失效的情况:

    1. 增删改都会刷新(删除)缓存
    2. 缓存不定时刷新(删除)
    3. 手动删除
    sqlSession.cleanCache();
    

    小结:一级缓存默认开启的,旨在一次SqlSession中有效,也就是连接到关闭连接这个区间,没啥用

13.4 二级缓存

步骤:

  1. 核心配置settings标签中开启二级缓存
//显示的开启全局缓存,,默认开启
<setting name="cacheEnabled" value="true"/>
  1. 在mapper中使用二级缓存,这些属性可以通过 cache 元素的属性来修改。比如:
<cacheeviction="FIFO"flushInterval="60000"size="512"readOnly="true"/>

提示:二级缓存是事务性的。这意味着,当 SqlSession 完成并提交时,或是完成并回滚,但没有执行 flushCache=true 的 insert/delete/update 语句时,缓存会获得更新。

一般二级缓存这一个就够了,但需要将实体类序列化

<cache/>

13.5 自定义缓存 Ehcache(不用)

复杂,工作会用redis,不会用这些,就不学了

小结:

  • 只要开启了二级缓存,在同一个Mapper下就有效
  • 所有的数据都会先放在一级缓存中
  • 如果出错了需要将实体类序列化

14、SMBMS完善 Mybatis

15、初识Spring

Mybatis (总结完整)相关推荐

  1. MyBatis学习--完整教程

    文章目录 MyBatis 1.简介 1.1 什么是Mybatis 1.2 持久化 1.3 持久层 1.4 为什么需要MyBatis 2.第一个Mybatis程序 2.1 搭建环境 2.2 创建一个模块 ...

  2. Springboot 整合 Mybatis 的完整 Web 案例

    2019独角兽企业重金招聘Python工程师标准>>> 摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢! 推荐一本书<腾讯 ...

  3. 如何实现 楼中楼评论(盖楼)spring boot + mybatis 附完整代码

    如何实现 楼中楼评论(盖楼) 理想效果: 需求分析 1. 实现用户评论功能(CRUD)--> 这里称之为父级评论 2. 能够对父级评论做出回复--> 这里称之为一级评论 3. 能够对一级评 ...

  4. Spring Boot 整合 Mybatis Annotation 注解的完整 Web 案例

    摘要: 原创出处 www.bysocket.com 「泥瓦匠BYSocket 」欢迎转载,保留摘要,谢谢! 『 公司需要人.产品.业务和方向,方向又要人.产品.业务和方向,方向- 循环』 本文提纲 一 ...

  5. SpringBoot整合Mybatis(高级)

    SpringBoot整合Mybatis(高级) 文章目录 SpringBoot整合Mybatis(高级) 前言 基础环境配置 增删改查 ResultMap 复杂查询 多对一 一对多 动态SQL if ...

  6. mybatis学习笔记-03-CRUD操作

    该视频为狂神说java视频配套笔记(博主自己手打223,日后做个参考223),b站连接:Mybatis最新完整教程IDEA版[通俗易懂]-03-CRUD操作) 3.CRUD 1.namespace ​ ...

  7. mybatis学习笔记-02-第一个mybatis程序

    该视频为狂神说java视频配套笔记(博主自己手打223,日后做个参考223),b站连接:Mybatis最新完整教程IDEA版[通俗易懂]-02-第一个mybatis程序) 文章目录 2.第一个myba ...

  8. mybatis学习笔记-01什么是mybatis

    该视频为狂神说java视频配套笔记(博主自己手打223,日后做个参考223),b站连接:Mybatis最新完整教程IDEA版[通俗易懂]-01-什么是mybatis 文章目录 1.简介 1.1是什么 ...

  9. 【Java从0到架构师】Spring - 整合 MyBatis

    整合 MyBatis 整合 MyBatis - 依赖 整合 MyBatis - 数据源 整合 MyBatis - SqlSessionFactoryBean 整合 MyBatis - MapperSc ...

  10. 一个项目了解 SpringBoot 集成 MyBatis

    SpringBoot 集成 MyBatis 创建项目 1.引入依赖 mybatis-spring-boot-starter 依赖 完整的 pom.xml 2.配置文件 加入mybatis配置 完整的配 ...

最新文章

  1. Java8 Optional,可以这样用啊
  2. 浏览器上的HTML5语音识别功能实例页面
  3. EL表达式中使用replace函数对时长字符串进行处理
  4. android 屏幕关闭 eofexception,android EOFException异常解决办法 (SharedPreferences保存对象)...
  5. 《Python编程从入门到实践》记录之类编码风格
  6. python函数分为哪几种_python数据挖掘常用工具有哪几种?
  7. 从BMW Vision iNEXT 看宝马如何进军自动驾驶 1
  8. linux 下安装gsl
  9. IOS 保存图片至相册
  10. 不到100行代码搞定Python做OCR识别身份证,文字等各种字体
  11. Android--存储权限
  12. GreenSock GSAP 3.0 最新版 所有内容创建于2020年4月4日
  13. 22东华大学计算机专硕854考研上岸实录
  14. 初级程序员需要掌握的知识
  15. opencascade基础
  16. jmeter_Ramp-up Period(in seconds)设置的作用及用法
  17. pytorch搭建Resnet50实现狗狗120个品种类的分类
  18. REDSHIFT学习笔记-渲染设置2_AOVOpt
  19. 大数据技术与应用-广东省赛总结
  20. sharepoint 2010 社区中心系统-在线问答-扩展讨论板Dicussion答复功能

热门文章

  1. Mac系统下如何创建锁屏快捷键
  2. python边缘坐标提取_python-从Shapely中的多边形中提取点/坐标
  3. 给文火慢炖的“少儿美术”加点料
  4. RabbitMQ入门前篇
  5. 51群接龙-社区社群团购专业营销工具
  6. 二手苹果电脑交易的坑和辨别真伪的一些方法总结(下篇)
  7. 盈米基金如何实现基金实时评价的百倍提速?
  8. JS复制文本到粘贴板,前端H5移动端点击按钮复制文本到粘贴板。
  9. 对于噪声数据理解以及Min-Max 规范化和 Score规范化(零-均值规范化)的实例【数据预处理】
  10. easyui Datagrid+searchbox 实现搜索功能