目录:
查看知识点请点击跳转!(笔记未写完)
引言
- Mybatis简介
- 第一个Mybatis程序 拓展知识:资源过滤
- 增删改查的实现
- 错误排查指导
- Map和模糊查询拓展
- 配置之属性优化
- 配置之别名优化与setting设置
- 配置之映射器说明
- 生命周期和作用域
- ResultMap映射
- 日志工厂
- Log4j讲解
- Limit实现分页
- PowBounds分页
- 使用注解开发
- Mybatis执行流程剖析
- 注解增删改查
- Lombok的使用
- 复杂查询环境搭建
- 多对一的处理
- 一对多的处理
- 动态SQL环境搭建
- 动态SQL之IF语句
- 动态SQL之常用标签
- 动态SQL之Foreach
- 缓存简介
- 一级缓存
- 二级缓存
- Mybatis缓存原理
- 自定义缓存Ehcache
- Mybatis总结
- 聊聊Spring这东西
资料整理来源于网络和b站狂神视频只用于笔记学习,如有侵权,请联系作者删除或者指明来源链接。
返回目录
引言:开始之前我大致学习了JDBC来操作数据库(JDBC:
https://blog.csdn.net/m0_57249797/article/details/118392897)然后数据库sql语句必须掌握(mysql:https://blog.csdn.net/m0_57249797/article/details/118392963)
比较:使用Mybatis与JDBC哪个更有优势
- Mybatis框架也是在JDBC上封装了一层,底层也是JDBC原理。
- 直接写JDBC代码的效率确实高,但是纯用JDBC,只要项目达到一定规模,那我们项目里的代码量就会非常多;最重要的是,很多代码都是重复的;如果我们项目里边积累了很多重复的代码,最致命的问题就是不好维护。
- 我听说过的运用持久化层的技术:JDBC/DBUtils/Spring JDBCTemplate/Hibernate/Mybatis
- 入门:使用Mybatis的步骤
1.引入pom依赖
2.Mybatis的配置文件
3.编写映射文件
4.得到sqlsession执行语句
5.关闭session
正式开始
根据b站狂神视频整理的笔记
Mybatis-9.28
环境:
- JDK1.8
- Mysql
- Maven
- IDEA
回顾:
- JDBC
- Mysql
- java基础
- Maven配置
{
Maven学习笔记:
https://blog.csdn.net/m0_57249797/article/details/118416714?spm=1001.2014.3001.5501
Ant学习笔记:
https://blog.csdn.net/m0_57249797/article/details/118416752?spm=1001.2014.3001.5501
} - Junit
SSM框架:配置文件的。最好的方式:看官网文档(Mybatis3中文文档,最新链接:https://mybatis.org/mybatis-3/zh/sqlmap-xml.html);
1.简介
1.1什么是Mybatis
- MyBatis 是一款优秀的持久层框架
- 它支持自定义 SQL、存储过程以及高级映射。
- MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
- MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
- MyBatis 本是apache的一个开源项目iBatis(iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)), 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。
- 2013年11月迁移到Github。
如何获得Mybatis?
- Maven仓库(个人建议)
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
- Github
- 中文文档
1.2 持久层
数据持久化
- 持久化就是将程序的数据在持久状态和瞬时状态转化的过程
- 内存:断电即失
- 数据库(jdbc),io文件持久化
- 生活:冷藏,罐头
为什么需要持久化 - 有一些对象不能让它丢掉
- 内存太贵了
1.3 持久层
Dao层,Service层,Controller层…
- 完成持久化工作的代码块
- 层界限十分明显
1.4 为什么需要Mybatis
- 帮助程序员将数据存入到数据库中
- 方便
- 传统的JDBC代码太复杂了。简化。框架。自动化。
- 不用Mybatis也可以,用它更容易上手。技术没有高低之分
- 优点:
1.简单易学
2.灵活
3.SQL和代码分离,提高了可维护性
4.提供映射(什么叫映射?是map/mapper直译过来的意思,就是汉语表达map/mapper)标签,支持对象与数据库的orm字段关系映射
5.提供对象关系映射标签,支持对象关系组建维护
6.提供xml标签,支持编写动态sql。
最重要的一点:使用的人多!!!
2.第一个Mybatis程序
返回目录
思路:搭建环境–>导入Mybatis–>编写代码–>测试
2.1搭建环境
搭建数据库
新建项目
- 新建一个普通的Maven项目
- 删除src目录
- 导入Maven依赖
<!--导入依赖-->
<dependencies>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--Mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<!--Junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
2.2 创建一个模块
- 编写mybatis的核心配置文件(我把时区设置为北京时间东八区)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration核心配置文件-->
<configuration>
<environments default="development">
<environment id="development">
<!-- transactionManager事务管理 -->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--useSSL=true&有问题-->
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&character=UTF-8&serverTimezone=GMT%2B8"/>
<property name="username" value="root"/>
<property name="password" value="198810"/>
</dataSource>
</environment>
</environments>
<!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册-->
<mappers>
<mapper resource="com/kuang/dao/UserMapper.xml"/>
<!-- <mapper class="com.kuang.dao.UserDao"/>-->
<!-- <package name="com.kuang.dao"/>-->
</mappers>
</configuration>
- 编写mybatis工具类
//sqlSessionFactory-->sqlSession
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
//使用Mybatis第一步:获取sqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
// 既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
// SqlSession 提供了在数据库执行 SQL 命令所需的所有方法(完全包含了面向数据库执行SQL命令所需的所有方法)
public static SqlSession getSqlSession(){
SqlSession sqlSession = sqlSessionFactory.openSession();//Ctrl+Alt+V补全对象创建
return sqlSession;
}
//至此可以对比JDBC完成connection对象创建,可以连接上数据库了。
}
2.3编写代码
- 实体类
package com.kuang.pojo;
public class User {
private int id;
private String name;
private String pwd;
public User() {
}
public User(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 {//等价于Mapper
List<User> getUserList();
}
- 接口实现类由原来UserDaoImpI转变为一个Mapper配置文件.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.kuang.dao.UserDao">
<!--select是查询语句标签-->
<!--记住两个常用的返回类型resultType和resultMap-->
<select id="getUserList" resultType="com.kuang.pojo.User">
select * from mybatis.user;//查询mybatis数据库下的user表中所有数据
</select>
</mapper>
2.4测试
资源过滤:
返回目录
在初学mybatis中,经常会报一个异常:
Caused by: org.apache.ibatis.exceptions.PersistenceException:
### Error building SqlSession.
### The error may exist in com/Adu/mapper/UserMapper.xml
### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: java.io.IOException: Could not find resource com/Adu/mapper/UserMapper.xml
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
原因:有时候IDEA不会加载除’.class’文件,所以我们要配置在pom.xml(最好所有)配置文件中加入(约定大于配置):
<build>
<resources>
<resource>
<directory>src/main/java</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>
MapperRegistry是什么?
核心配置文件注册mappers
- junit测试
public class UserDaoTest {
@Test
public void set(){
//第一步:获取SqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//执行SQL
UserDao userDao = sqlSession.getMapper(UserDao.class);
List<User> userList = userDao.getUserList();
for(User user:userList){
System.out.println(user);
}
//关闭SqlSession
sqlSession.close();
}
}
- 可能遇到的问题:
1.配置文件没有注册
2.绑定接口错误
3.方法名不对
4.返回类型不对
5.Maven导出资源问题
学完后展示一下目录结构:
我个人还遇到了SSL连接问题。尚未解决
以下是b站狂神视频目录,逐步写成笔记
3.增删改查的实现(CRUD)
返回目录
1.namespace
- 将上面案例中的UserMapper接口改名为 UserDao;
- 将UserMapper.xml中的namespace改为为UserDao的路径 .
- 再次测试
配置文件中namespace中的名称为对应Mapper接口或者Dao接口的完整包名,必须一致!
注意点:增、删、改操作需要提交事务!
2.实现增删改查的接口方法
//根据ID查询用户
User getUserById(int id);
//insert一个用户
int addUser(User user);
//修改用户
int updateUser(User user);
//删除用户
int deleteUser(int id);
//建议写法:int deleteUser(@Param("id") int id);//@Param("id") 在只有一个参数的情况下可以省略
3.xml的映射配置文件
<select id="getUserById" parameterType="int" resultType="com.kuang.pojo.User">
select * from mybatis.user where id=#{id};
</select>
<insert id="addUser" parameterType="com.kuang.pojo.User">
insert into mybatis.user (id,name,pwd) values (#{id},#{name},#{pwd});
</insert>
<update id="updateUser" parameterType="com.kuang.pojo.User">
update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id};
</update>
<delete id="deleteUser" parameterType="int">
delete from mybatis.user where id=#{id};
</delete>
3.测试方法
//CRUD
@Test
public void getUserById(){
//第一步:获取SqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
//执行SQL
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user=mapper.getUserById(1);
//System.out.println(userList.get(0).getName());
System.out.println(user);
//关闭SqlSession
sqlSession.close();
}
@Test
public void addUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//执行SQL
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.addUser(new User(4,"t","123"));
sqlSession.commit();
sqlSession.close();
}
@Test
public void updateUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//执行SQL
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.updateUser(new User(4,"你","1223"));
sqlSession.commit();
sqlSession.close();
}
@Test
public void deleteUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//执行SQL
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
System.out.println( mapper.deleteUser(4));
sqlSession.commit();
sqlSession.close(); mapper.deleteUser(4);
}
要点:
- 所有的增删改操作都需要提交事务!
- 接口所有的普通参数,尽量都写上@Param参数,尤其是多个参数时,必须写上!
- 有时候根据业务的需求,可以考虑使用map传递参数!(后面介绍)
- 为了规范操作,在SQL的配置文件中,我们尽量将Parameter参数和resultType都写上!
4.错误排查指导
- 标签不要匹配错
- resource绑定mapper,需要使用路径
- 程序配置文件必须符合规范
- NullPointerException,没有注册到资源
- 输出的xml文件存在中文乱码问题
- Maven资源没有导出问题
5.Map和模糊查询拓展
返回目录
课堂练习:根据 密码 和 名字 查询用户
思路一:直接在方法中传递参数
1、在接口方法的参数前加 @Param属性
2、Sql语句编写的时候,直接取@Param中设置的值即可,不需要单独设置参数类型
//通过密码和名字查询用户
User selectUserByNP(@Param("username") String username,@Param("pwd") String pwd);
/*
<select id="selectUserByNP" resultType="com.kuang.pojo.User">
select * from user where name = #{username} and pwd = #{pwd}
</select>
*/
思路二:使用万能的Map
1、在接口方法中,参数直接传递Map;
User selectUserByNP2(Map<String,Object> map);
2、编写sql语句的时候,需要传递参数类型,参数类型为map
<select id="selectUserByNP2" parameterType="map" resultType="com.kuang.pojo.User">
select * from user where name = #{username} and pwd = #{pwd}
</select>
3、在使用方法的时候,Map的 key 为 sql中取的值即可,没有顺序要求!
Map<String, Object> map = new HashMap<String, Object>();
map.put("username","小明");
map.put("pwd","123456");
User user = mapper.selectUserByNP2(map);
总结:如果参数过多,我们可以考虑直接使用Map实现,如果参数比较少,直接传递参数即可
模糊查询like语句该怎么写?
第1种:在Java代码中添加sql通配符。
UserMapper接口中添加方法:
List<User> selectlike(String value);
映射文件中配置:
<select id="selectlike" resultType="com.kuang.pojo.User">
select * from user where name like #{value}
</select>
测试代码:
public void test02(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//执行SQL
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
String wildcardname = "%李%";
List<User> names = mapper.selectlike(wildcardname);
for (User name : names) {
System.out.println(name);
}
sqlSession.close();
}
结果:
第2种:在sql语句中拼接通配符,会引起sql注入
映射文件改变:
<select id="selectlike" resultType="com.kuang.pojo.User">
select * from user where name like "%"#{value}"%";
</select>
6.配置之属性优化
返回目录
解析引入:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration核心配置文件-->
<configuration>
<environments default="development"><!--default为默认使用哪个数据库环境的id属性名-->
<!--下面为我的第一套数据库,id为环境名-->
<environment id="development"><!--id为环境名-->
<!-- transactionManager事务管理 -->
<transactionManager type="JDBC"/><!--事务管理器-->
<dataSource type="POOLED"><!--数据源(常见:c3p0和DBCP、druid)-->
<!--我们可以设置property属性来实现配置文件-->
<!--这些属性都是可以外部配置且可以动态替换的,既可以在典型的java属性文件中配置,亦可通过properties元素的子元素来传递[db.properties]-->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--useSSL=true&有问题-->
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&useSSL=false&character=UTF-8&serverTimezone=GMT%2B8"/>
<property name="username" value="root"/>
<property name="password" value="198810"/>
</dataSource>
</environment>
<!--下面为我的第二套数据库,id为环境名-->
<environment id="sql02">
<!-- transactionManager事务管理 -->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--useSSL=true&有问题-->
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&useSSL=false&character=UTF-8&serverTimezone=GMT%2B8"/>
<property name="username" value="root"/>
<property name="password" value="198810"/>
</dataSource>
</environment>
</environments>
<!--每一个Mapper.xml都需要在Mybatis核心配置文件中注册-->
<mappers>
<mapper resource="com/l/dao/UserMapper.xml"/>
</mappers>
</configuration>
注:<transactionManager type=“JDBC”/>下的属性和属性值用不上,可以暂时忽略不写
属性优化(properties)
我们可以通过properties属性来实现引用配置文件
这些属性都是可以外部配置且可以动态替换的,既可以在典型的java属性文件中配置,亦可通过properties元素的子元素来传递【db.properties】
编写一个配置文件:
在resource下建立db.properties并写上如下配置:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&useSSL=false&character=UTF-8&serverTimezone=GMT%2B8
username=root
password=198810
在核心配置文件中引入
(在xml中,所有的标签都可以规定其顺序)
<properties resource="db.properties"><!--第一步引入外部配置文件-->
<property name="username" value="root"/>
<property name="password" value="123456"/>
</properties>
完整代码:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.properties"><!--第一步引入外部配置文件-->
<property name="username" value="root"/>
<property name="password" value="123456"/>
</properties>
<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>
<mapper resource="com/l/dao/UserMapper.xml"/>
</mappers>
</configuration>
注意点:
- 可以直接引入外部文件
- 可以在其中增加一些属性配置
- 如果两个文件有同一个字段优先使用外部配置文件的
7.配置之别名优化与setting设置
返回目录
代码:
第一种取别名的方式,指定类:
<typeAliases>
<typeAlias type="com.l.pojo.User" alias="User"/>
</typeAliases>
映射文件:
<select id="getUserList" resultType="User">
select * from mybatis.user;
</select>
第二种取别名的方式,指定包(别名就为类名【首字母可大小写,官方建议小写】):
<typeAliases>
<package name="com.l.pojo"/>
</typeAliases>
映射文件:
<select id="getUserList" resultType="User">
select * from mybatis.user;
</select>
第三种,在扫描包的情况下,我们也使用@Alias注解来实现其他别名的设置
映射文件:
<select id="getUserList" resultType="U">
select * from mybatis.user;
</select>
setting设置
8.配置之映射器说明
返回目录
MapperRegistry:注册绑定我们的Mapper文件;
方式一:【推荐使用】
<!-- 使用相对于类路径的资源引用 -->
<!--每一个Mapper.xml都需要在MyBatis核心配置文件中注册-->
<mappers>
<mapper resource="com/l/dao/UserMapper.xml"/>
</mappers>
方式二:
通过类名(属性值配置的是接口名)去注册:
<!--
使用映射器接口实现类的完全限定类名
需要配置文件名称和接口名称一致,并且位于同一目录下
-->
<mappers>
<mapper class="com.l.dao.UserMapper"/>
</mappers>
使用方式二的注意点:
- 接口和它的Mapper配置文件必须同名
- 接口和它的Mapper配置文件必须在同一包下
方式三:使用扫描包进行注入绑定
<!--
将包内的映射器接口实现全部注册为映射器
但是需要配置文件名称和接口名称一致,并且位于同一目录下
-->
<mappers>
<package name="com.l.dao"/>
</mappers>
目录结构:
9.生命周期和作用域
返回目录
上面的每一个Mapper,就代表一个具体的业务!
10.ResultMap映射
解决属性名和字段名不一致的问题
数据库中的字段:
新建一个项目,拷贝之前的,测试实体类字段不一致的情况
public class User {
private int id;
private String name;
private String password;
}
映射文件:
<select id="getUserById" parameterType="int" resultType="com.l.pojo.User">
select * from mybatis.user where id=#{id};
</select>
查询结果:
分析:
- select * from user where id = #{id} 可以看做
- select id,name,pwd from user where id = #{id}
- mybatis会根据这些查询的列名(会将列名转化为小写,数据库不区分大小写) , 去对应的实体类中查找相应列名的set方法设值 , 由于找不到setPwd() , 所以password返回null ; 【自动映射】
解决方案
方案一:为列名指定别名 , 别名和java实体类的属性名一致 .
<select id="selectUserById" resultType="User">
select id , name , pwd as password from user where id = #{id}
</select>
方案二:使用结果集映射->ResultMap 【推荐】
<resultMap id="UserMap" type="User">
<!-- id为主键 -->
<id column="id" property="id"/>
<!-- column是数据库表的列名 , property是对应实体类的属性名 -->
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
<select id="selectUserById" resultMap="UserMap">
select * from user where id = #{id}
</select>
11.日志工厂
- 思考:我们在测试SQL的时候,要是能够在控制台输出 SQL 的话,是不是就能够有更快的排错效率?
- 如果一个数据库操作,出现了异常,我们需要排错。日志就是最好的助手!
- 如果一个 数据库相关的操作出现了问题,我们可以根据输出的SQL语句快速排查问题。
曾经:sout、debug
现在:日志工厂(对于以往的开发过程,我们会经常使用到debug模式来调节,跟踪我们的代码执行过程。但是现在使用Mybatis是基于接口,配置文件的源代码执行过程。因此,我们必须选择日志工具来作为我们开发,调节程序的工具)
Mybatis内置的日志工厂提供日志功能,具体的日志实现有以下几种工具:
- SLF4J
- Apache Commons Logging
- Log4j 2
- JDK logging
- Log4j【掌握】
- STDOUT_LOGGING【掌握】
具体选择哪个日志实现工具由MyBatis的内置日志工厂确定。它会使用最先找到的(按上文列举的顺序查找)。如果一个都未找到,日志功能就会被禁用。
STDOUT_LOGGING标准日志输出
在核心配置文件中配置日志:
<settings>
<!--标准的日志工厂实现-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
运行测试输出日志结果:
12.Log4j讲解
返回目录
简介:
- Log4j是Apache的一个开源项目
- 通过使用Log4j,我们可以控制日志信息输送的目的地:控制台,文本,GUI组件…
- 我们也可以控制每一条日志的输出格式;
- 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
使用步骤:
1、导入log4j的包
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2、配置文件编写(在resource下建立log4j.properties文件)
#将等级为DEBUG的日志信息输出到console和file这两个目的地,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/kuang.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
运行查询代码
结果:
简单使用:
1.在要使用Log4j的类中,导入包 import org.apache.log4j.Logger;
2.日志对象,参数为当前类的class,范围为全局变量
static Logger logger = Logger.getLogger(UserDaoTest.class);
3.日志级别
logger.info("info:进入getUserById方法");
logger.debug("debug:进入getUserById方法");
logger.error("error: 进入getUserById方法");
4.测试代码:
public void test() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
logger.info("info:进入getUserById方法成功");
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
logger.debug("debug:进入getUserById方法");
User user = mapper.getUserById(1);
logger.error("error: 进入getUserById方法");
System.out.println(user);
sqlSession.close();
}
结果:
可以看到还生成了一个日志的文件 【需要修改file的日志级别】
13.Limit实现分页
思考:为什么需要分页?
- 减少数据的处理量
在学习mybatis等持久层框架的时候,会经常对数据进行增删改查操作,使用最多的是对数据库进行查询操作,如果查询大量数据的时候,我们往往使用分页进行查询,也就是每次处理小部分数据,这样对数据库压力就在可控范围内。
使用Limit实现分页
普通sql语句查询语法:
#语法
SELECT * FROM table LIMIT stratIndex,pageSize
#操作
SELECT * FROM table LIMIT 5,10; // 检索记录行 6-15
#如果只给定一个参数,它表示返回最大的记录行数目:
SELECT * FROM table LIMIT 5; //检索前 5 个记录行
#换句话说,LIMIT n 等价于 LIMIT 0,n。
mybatis实现分页查询:
步骤:
1、修改映射文件:
<select id="selectUser" parameterType="map" resultType="user">
select * from user limit #{startIndex},#{pageSize}
</select>
2、接口中增加方法,参数为map(建议多使用万能的map)
//选择全部用户实现分页
List<User> selectUser(Map<String,Integer> map);
3、在测试类中传入参数测试
- 推断:起始位置 = (当前页面 - 1 ) * 页面大小
@Test
public void test02() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String,Integer> map=new HashMap<String, Integer>();
map.put("startIndex",0);
map.put("pageSize",3);
List<User> user = mapper.SelectUser(map);
for (User user1 : user) {
System.out.println(user1);
}
sqlSession.close();
}
结果:
14.PowBounds分页
返回目录
我们除了使用Limit在SQL层面实现分页,也可以使用RowBounds在Java代码层面实现分页,当然此种方式作为了解即可。我们来看下如何实现的!
步骤:
1、mapper接口
//选择全部用户RowBounds实现分页
List<User> getUserByRowBounds();
2、mapper文件
<select id="getUserByRowBounds" resultMap="user">
select * from user
</select>
3、测试类
在这里,我们需要使用RowBounds类
@Test
public void testUserByRowBounds() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
int currentPage = 2; //第几页
int pageSize = 2; //每页显示几个
RowBounds rowBounds = new RowBounds((currentPage-1)*pageSize,pageSize);
//通过session.**方法进行传递rowBounds,[此种方式现在已经不推荐使用了]
List<User> users = sqlSession.selectList("com.l.dao.UserMapper.getUserByRowBounds", null, rowBounds);
for (User user: users){
System.out.println(user);
}
sqlSession.close();
}
15.使用注解开发
返回目录
注意:利用注解开发就不需要mapper.xml映射文件了删除!
1、注解在接口上实现
@Select("select * from user;")
List<User> getUsers();
2、需要在核心配置文件中绑定接口!
<!--绑定接口-->
<mappers>
<mapper class="com.l.dao.UserMapper"/>
</mappers>
3、测试使用
@Test
public void getUserById(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//底层主要应用反射
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> user=mapper.getUsers();
for (User user1 : user) {
System.out.println(user1);
}
sqlSession.close();
}
结果:这里的密码为空,自己改一下User类密码属性名就行了
本质:反射机制实现
底层:动态代理
利用Debug查看本质:
本质上利用了jvm的动态代理机制
16.Mybatis执行流程剖析
Mybatis详细的执行流程
17.注解增删改查
返回目录
我们可以在工具类创建的时候实现自动提交事务!,不用再写commit方法了
//工具类中创建sqlSession改为下面代码
SqlSession sqlSession = sqlSessionFactory.openSession(true);
注解实现CRUD:
//查询所有的用户
@Select("select * from user;")
List<User> getUsers();
/*方法存在多个参数,所有的参数面前必须添加@Param("")*/
@Select("select * from user where id=#{id} and name=#{name}")
User getUserById(@Param("id")int id,@Param("name")String name);
//增加一个用户
@Insert("insert into user(id,name,pwd) values(#{id},#{name},#{pwd})")
int addUser(User user);
//更新一条用户数据
@Update("update user set name=#{name},pwd=#{pwd} where id = #{id}")
int updateUser(User user);
//根据id删除用用户
@Delete("delete from user where id = #{id}")
int deleteUser(@Param("id")int id
测试方法:
package com.l.dao;
import com.l.pojo.User;
import com.l.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class UserDaoTest {
@Test
public void getUsers(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//底层主要应用反射
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> user=mapper.getUsers();
for (User user1 : user) {
System.out.println(user1);
}
sqlSession.close();
}
@Test
public void getUserById(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user=mapper.getUserById(2,"李四");
System.out.println(user);
sqlSession.close();
}
@Test
public void addUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
System.out.println(mapper.addUser(new User(5,"李奶奶","1112")));
sqlSession.close();
}
@Test
public void updateUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
System.out.println(mapper.updateUser(new User(5,"李奶奶个腿","11112222")));
sqlSession.close();
}
@Test
public void deleteUser(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
System.out.println(mapper.deleteUser(5));
sqlSession.close();
}
}
再提一下@Param注解,
- 基本数据类型的参数或者String类型,需要加上
- 引用数据类型不需要加
- 如果只有一个基本类型的话,可以忽略,但是建议大家加上
- 我们在SQL中引用的就是我们这里的@Param()中设定的属性名
18.Lombok的使用
返回目录
简介:
- java library
- plugs
- build tools
- with one annotation your class
使用步骤:
-
在IDEA中安装Lombok(设置-搜索插件-下载)
-
在项目中导入lombok的jar包
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
@Data注解帮我们自动封装无参构造,getter、setter方法,equals方法,hashCode方法,toString方法还有个canEqual方法
@ToString:生成toString方法
@EqualsAndHashCode生成equals和hashCode方法
@AllArgsConstructor生成有参构造方法
@NoArgsConstructor生成无参构造方法
@Getter生成getter方法,可以放在类或相应属性上
19.复杂查询环境搭建
返回目录
多个学生,对应一个老师
对于学生这边而言,关联… 多个学生,关联一个老师【多对一】
对于老师而言,集合,一个老师,有很多学生
学生通过tid关联老师的id
CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老师');
CREATE TABLE `student` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT 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');
测试环境搭建:
- 导入lombok
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
- 新建实体类 Teacher,Student
@Data
public class Teacher {
private int id;
private String name;
}
@Data
public class Student {
private int id;
private String name;
//学生需要关联一个老师
private Teacher teacher;
}
- 建立Mapper接口
public interface StudentMapper {
}
public interface TeacherMapper {
@Select("select * from teacher where id=#{tid}")
Teacher getTeacher(@Param("tid")int id);
}
- 建立Mapper.xml接口
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.l.dao.TeacherMapper">
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.l.dao.StudentMapper">
</mapper>
-
在核心配置文件中绑定注册我们的Mapper接口或者文件!【方式很多,随心选】
-
测试查询是否成功
查询类:
public static void main(String[] args) {
SqlSession sqlSession= MybatisUtils.getSqlSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacher=mapper.getTeacher(1);
System.out.println(teacher);
sqlSession.close();
}
结构图:
在resources下映射相同路径就不用再写资源过滤了
运行结果
20.多对一的处理
返回目录
引言:
在sql语句中想要多对一查询的语句:
select student.id,student.name,teacher.name from student,teacher where student.id=teacher.id
结果:
在mybatis中就没有那么简单了
方式一、按照查询嵌套处理(了解):
在StudentMapper.xml中配置:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.l.dao.StudentMapper">
<!--
思路:
1.查询所有的学生信息
2.根据查询出来的学生的tid,寻找对应的老师
相当于子查询
-->
<select id="getStudent" resultMap="StudentTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="com.l.pojo.Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!--复杂的属性,我们需要单独处理 对象:association 集合:collection-->
<association property="teacher" column="tid" javaType="com.l.pojo.Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="com.l.pojo.Teacher">
select * from teacher where id=#{id}
</select>
</mapper>
测试:
@org.junit.Test
public void test01(){
SqlSession sqlSession= MybatisUtils.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> student = mapper.getStudent();
for (Student student1 : student) {
System.out.println(student1);
}
sqlSession.close();
}
运行结果:
方式二、按照结果嵌套处理(掌握):
StudentMapper接口新加方法:
public List<Student> getStudent02();
StudentMapper.xml配置:
<select id="getStudent02" resultMap="StudentTeacher02">
select student.id,student.name,teacher.name
from student,teacher
where student.tid=teacher.id
</select>
<resultMap id="StudentTeacher02" type="com.l.pojo.Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<association property="teacher" javaType="com.l.pojo.Teacher">
<result property="name" column="name"/>
</association>
</resultMap>
测试:
@org.junit.Test
public void test02(){
SqlSession sqlSession= MybatisUtils.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> student = mapper.getStudent02();
for (Student student1 : student) {
System.out.println(student1);
}
sqlSession.close();
}
结果:
21.一对多的处理
返回目录
比如一个老师有多个学生
第一步还是环境搭建:
实体类:Student和Teacher
@Data
public class Student {
private int id;
private String name;
private int tid;
}
@Data
public class Teacher {
private int id;
private String name;
private List<Student> student;
}
对应的接口
public interface StudentMapper {
}
public interface TeacherMapper {
//获取老师
List<Teacher> getTeacher();
}
TeacherMapper.xml配置:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.l.dao.TeacherMapper">
<select id="getTeacher" resultType="com.l.pojo.Teacher">
select * from mybatis.teacher
</select>
</mapper>
主配置:
db.properties文件:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&useSSL=false&character=UTF-8&serverTimezone=GMT%2B8
username=root
password=198810
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.properties"><!--第一步引入外部配置文件-->
<property name="username" value="root"/>
<property name="password" value="123456"/>
</properties>
<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="com.l.dao"/>
</mappers>
</configuration>
测试:
@org.junit.Test
public void test01(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
List<Teacher> teacher = mapper.getTeacher();
for (Teacher teacher1 : teacher) {
System.out.println(teacher1);
}
}
结果:
环境搭建成功!!!
引言:
在sql语句中想要多对一查询的语句:
select student.id sid,student.name sname,teacher.name tname,teacher.id tid from teacher,student where tid=teacher.id;
结果:
方式一、按照查询嵌套处理(了解):
<select id="getTeacher2" resultMap="TeacherStudent2">
select * from mybatis.teacher where id=#{id}
</select>
<resultMap id="TeacherStudent2" type="com.l.pojo.Teacher">
<collection property="students" column="id" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId"/>
</resultMap>
<select id="getStudentByTeacherId" resultType="com.l.pojo.Student">
select * from mybatis.student where tid=${tid}
</select>
方式二、按照结果嵌套处理(掌握):
TeacherMapper.xml中的配置:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.l.dao.TeacherMapper">
<select id="getTeacher" resultMap="TeacherStudent">
select student.id sid,student.name sname,teacher.name tname,teacher.id tid
from teacher,student where student.tid=teacher.id and teacher.id=#{tid};
</select>
<resultMap id="TeacherStudent" type="com.l.pojo.Teacher">
<!--
在结果嵌套查询中
对象用:association
集合用:collection
javaType:指定属性类型
ofType:集合中的泛型信息
显而易见:在多对一中association常搭配javaType
在一对多中collection常搭配ofType
-->
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<collection property="students" ofType="com.l.pojo.Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
</mapper>
其余不变的情况下,修改测试方法:
@org.junit.Test
public void test02(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
teacher = mapper.getTeacher(1);
System.out.println(teacher.getName());
sqlSession.close();
}
结果: