Mybatis (总结完整)
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&useSSL=false&useUnicode=true&characterEncoding=utf-8&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 简介
- 什么是缓存【Cache】?
- 存在内存中的临时数据
- 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存查询,从而提高查询效率,解决了高并发系统的性能问题。
- 为什么使用缓存?
- 减少和数据库交互的次数,减少系统开销,提高系统效率
- 什么样的数据能使用缓存?
- 经常查询并且不经常改变的数据。
13.2 Mybatis缓存
- Mybatis包含一个非常强大的查询缓存特性,它可以非常方便的定制和配置缓存。缓存可以极大的提升查询效率。
- Mybatis系统中默认定义了两级缓存:一级缓存和二级缓存
- 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)
- 二级缓存需要手动开启和配置,他是基于namespace级别的缓存
- 为了提高扩展性,Mybatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存
13.3 一级缓存(没啥用)
- 一级缓存也叫本地缓存:SqlSession
- 与数据库同一次会话期间查询到的数据会放在本地缓存中
- 以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库
测试步骤:
- 开启日志
- 测试再一次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();
}
观察日志发现sql只查询了一次
缓存失效的情况:
- 增删改都会刷新(删除)缓存
- 缓存不定时刷新(删除)
- 手动删除
sqlSession.cleanCache();
小结:一级缓存默认开启的,旨在一次SqlSession中有效,也就是连接到关闭连接这个区间,没啥用
13.4 二级缓存
步骤:
- 核心配置settings标签中开启二级缓存
//显示的开启全局缓存,,默认开启
<setting name="cacheEnabled" value="true"/>
- 在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 (总结完整)相关推荐
- MyBatis学习--完整教程
文章目录 MyBatis 1.简介 1.1 什么是Mybatis 1.2 持久化 1.3 持久层 1.4 为什么需要MyBatis 2.第一个Mybatis程序 2.1 搭建环境 2.2 创建一个模块 ...
- Springboot 整合 Mybatis 的完整 Web 案例
2019独角兽企业重金招聘Python工程师标准>>> 摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢! 推荐一本书<腾讯 ...
- 如何实现 楼中楼评论(盖楼)spring boot + mybatis 附完整代码
如何实现 楼中楼评论(盖楼) 理想效果: 需求分析 1. 实现用户评论功能(CRUD)--> 这里称之为父级评论 2. 能够对父级评论做出回复--> 这里称之为一级评论 3. 能够对一级评 ...
- Spring Boot 整合 Mybatis Annotation 注解的完整 Web 案例
摘要: 原创出处 www.bysocket.com 「泥瓦匠BYSocket 」欢迎转载,保留摘要,谢谢! 『 公司需要人.产品.业务和方向,方向又要人.产品.业务和方向,方向- 循环』 本文提纲 一 ...
- SpringBoot整合Mybatis(高级)
SpringBoot整合Mybatis(高级) 文章目录 SpringBoot整合Mybatis(高级) 前言 基础环境配置 增删改查 ResultMap 复杂查询 多对一 一对多 动态SQL if ...
- mybatis学习笔记-03-CRUD操作
该视频为狂神说java视频配套笔记(博主自己手打223,日后做个参考223),b站连接:Mybatis最新完整教程IDEA版[通俗易懂]-03-CRUD操作) 3.CRUD 1.namespace ...
- mybatis学习笔记-02-第一个mybatis程序
该视频为狂神说java视频配套笔记(博主自己手打223,日后做个参考223),b站连接:Mybatis最新完整教程IDEA版[通俗易懂]-02-第一个mybatis程序) 文章目录 2.第一个myba ...
- mybatis学习笔记-01什么是mybatis
该视频为狂神说java视频配套笔记(博主自己手打223,日后做个参考223),b站连接:Mybatis最新完整教程IDEA版[通俗易懂]-01-什么是mybatis 文章目录 1.简介 1.1是什么 ...
- 【Java从0到架构师】Spring - 整合 MyBatis
整合 MyBatis 整合 MyBatis - 依赖 整合 MyBatis - 数据源 整合 MyBatis - SqlSessionFactoryBean 整合 MyBatis - MapperSc ...
- 一个项目了解 SpringBoot 集成 MyBatis
SpringBoot 集成 MyBatis 创建项目 1.引入依赖 mybatis-spring-boot-starter 依赖 完整的 pom.xml 2.配置文件 加入mybatis配置 完整的配 ...
最新文章
- Java8 Optional,可以这样用啊
- 浏览器上的HTML5语音识别功能实例页面
- EL表达式中使用replace函数对时长字符串进行处理
- android 屏幕关闭 eofexception,android EOFException异常解决办法 (SharedPreferences保存对象)...
- 《Python编程从入门到实践》记录之类编码风格
- python函数分为哪几种_python数据挖掘常用工具有哪几种?
- 从BMW Vision iNEXT 看宝马如何进军自动驾驶 1
- linux 下安装gsl
- IOS 保存图片至相册
- 不到100行代码搞定Python做OCR识别身份证,文字等各种字体
- Android--存储权限
- GreenSock GSAP 3.0 最新版 所有内容创建于2020年4月4日
- 22东华大学计算机专硕854考研上岸实录
- 初级程序员需要掌握的知识
- opencascade基础
- jmeter_Ramp-up Period(in seconds)设置的作用及用法
- pytorch搭建Resnet50实现狗狗120个品种类的分类
- REDSHIFT学习笔记-渲染设置2_AOVOpt
- 大数据技术与应用-广东省赛总结
- sharepoint 2010 社区中心系统-在线问答-扩展讨论板Dicussion答复功能
热门文章
- Mac系统下如何创建锁屏快捷键
- python边缘坐标提取_python-从Shapely中的多边形中提取点/坐标
- 给文火慢炖的“少儿美术”加点料
- RabbitMQ入门前篇
- 51群接龙-社区社群团购专业营销工具
- 二手苹果电脑交易的坑和辨别真伪的一些方法总结(下篇)
- 盈米基金如何实现基金实时评价的百倍提速?
- JS复制文本到粘贴板,前端H5移动端点击按钮复制文本到粘贴板。
- 对于噪声数据理解以及Min-Max 规范化和 Score规范化(零-均值规范化)的实例【数据预处理】
- easyui Datagrid+searchbox 实现搜索功能