前置知识:JDBC
学习视频
Mybatis——一种ORM框架:将Java中的Bean映射为数据库的记录
Mybatis运行过程——工厂模式
#{}
与 ${}
——三点区别
动态Sql
分页——两种方法
缓存——查询缓存顺序
官方文档
下载链接
sql相关
JDBC驱动程序:JDBC(Java Database Connectivity, Java 数 据 库 连 接)是 一 种可用于执行 SQL 语句的 Java API(Application Programming Interface)
实现了从 Java 程序内调用标准的 SQL命令
对数据库进行查询、插入、删除和更新等操作, 并确保数据事务的正常进行
基本层次结构由 Java 程序、JDBC 驱动程序管理器、数据库驱动程序和数据库四部分组成
Java 程序依赖于 JDBC API,通过 DriverManager
来获取驱动,并且针对不同的数据库可以使用不同的驱动。
这是典型的桥接的设计模式,把 抽象 Abstraction
与 行为实现Implementation 分离
开来,从而可以保持各部分的独立性以及应对他们的功能扩展。
public static void connectionTest(){
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
// 1. 加载并注册 MySQL 驱动器实例
Class.forName("com.mysql.cj.jdbc.Driver").newInstance();
// 2. 将Mysql驱动程序注册到驱动管理程序中
// 根据特定的数据库连接URL,返回与此URL所匹配的数据库驱动对象
Driver driver = DriverManager.getDriver("jdbc:mysql://localhost:3306/[dbName]");
// 3. 传入参数,比如说用户名和密码
Properties props = new Properties();
props.put("user", USER_NAME);
props.put("password", PASSWORD);
// 4. 使用数据库驱动创建数据库连接 Connection
connection = driver.connect(URL, props);
// 5. 从数据库连接 connection 中获得 Statement 对象
statement = connection.createStatement();
// 6. 执行 sql 语句,返回结果
resultSet = statement.executeQuery("select * from activity");
// 7. 处理结果,取出数据
while(resultSet.next()){
System.out.println(resultSet.getString(2));
}
.....
}finally{
// 8.关闭链接,释放资源 按照JDBC的规范,使用完成后管理链接,
// 释放资源,释放顺序应该是: ResultSet ->Statement ->Connection
resultSet.close();
statement.close();
connection.close();
}
}
持久层框架
持久化:将程序中的数据从 瞬时状态【内存:断电即失】转化为 持久状态【数据库jdbc,io文件持久化】的过程
持久层:完成数据持久化工作的代码块,层次间界限分明
定制化Sql
避免JDBC代码,手动设置参数和获取结果集
优点
通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO
SqlSessionFactoryBuilder
SqlsessionFactory
executor
SqlSession
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.6version>
dependency>
一旦创建了 SqlSessionFactory
,就不再需要它了。
因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心
构造方法:从xml中配置文件中构建SqlSessionFactory实例
SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在
- 作用域:应用作用域
最简单的就是使用单例模式或者静态单例模式。
通过 SqlSessionFactory
获得 SqlSession
的实例。
SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
SqlSession的实例时线程不安全的,不能被共享
- 每次收到一个数据库访问请求,打开一个SqlSession,返回响应后,立即关闭
代理对象 执行具体业务
将接口与xml进行绑定
create table user(
id int(11) not null primary key,
user_name varchar(30) default null,
pwd varchar(30) default null
)engine=InnoDB default charset=utf8;
insert into user(id,user_name,pwd) values
(1,'a','123456'),
(2,'b','123456'),
(3,'c','c123456');
<groupId>com.kuang.MyBatisgroupId>
<artifactId>MyBatisartifactId>
<version>1.0-SNAPSHOTversion>
<dependencies>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.16version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.6version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
dependencies>
DOCTYPE configuration
PUBLIC "-//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?useSSL=true&useUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="2017002231"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/kuang/dao/UserMapper.xml"/>
mappers>
configuration>
新建dao包,utils包
public class MyBatisUtils {
private static SqlSessionFactory sqlSessionFactory;
// 1.获取SqlSessionFactory对象
static{
try {
//1. 将资源中的配置文件以流的形式读入
String resource = "mybatis-config.xml";
InputStream configuration = Resources.getResourceAsStream(resource);
//2. 通过工厂类构建器构建SqlSessionFactory类
sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
} catch (IOException e) {
e.printStackTrace();
}
}
// 2.获取SqlSession对象
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
pojo的作用就是将从数据库获取到的数据封装为一个一个的对象,让java能够更好的进行操作DO、VO
package com.kuang.pojo;
public class User {
private Integer id;
private String user_name;
private String pwd;
public User(){}
public User(Integer id, String user_name, String pwd) {
this.id = id;
this.user_name = user_name;
this.pwd = pwd;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUser_name() {
return user_name;
}
public void setUser_name(String user_name) {
this.user_name = user_name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", user_name='" + user_name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
public interface UserDao{
List<User> getUserList();
}
由 UserDaoImpl 转化为 Mapper 配置文件
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kuang.dao.UserDao">
<select id="getUserList" resultType="com.kuang.pojo.User">
select *from mybatis.user;
select>
mapper>
新建 测试类
编写测试代码
package com.kuang.dao;
import com.kuang.pojo.User;
import com.kuang.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class UserDaoTest {
@Test
public void test(){
//1.获取SqlSession对象
SqlSession sqlSession = MyBatisUtils.getSqlSession();
//2.执行Sql
//通过反射机制,获取方法区中UserMapper的Class类实例,这个实例中有UserMapper全部信息
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = userMapper.getUserList();
/*
//方式二:强制类型转换,不安全
List userList = sqlSession.selectOne("com.kuang.UserDao.getUserList");
*/
for (User user:userList){
System.out.println(user);
}
//关闭sqlSession
sqlSession.close();
}
}
执行UserDaoTest的test方法之前,要先 mvn test-compile 生成 test classes才可被部署并发现
<mappers>
<mapper resource="com/kuang/dao/UserMapper.xml"/>
mappers>
Maven约定大于配置,自己写的配置文件默认不会被导出或生效
Maven默认的资源(自己配置的xml)位置在resources目录下,当前项目的xml位于java目录下,所以找不到
<build>
<resources>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.propertesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
resources>
build>
CUD 需要通过connection对象以Transition(事务)的形式提交
选择,查询语句:
通过id获取用户
并没有新增
当字段过多时,考虑使用 Map,可以自定义需要传递的参数
configuration(配置)
通过Properties引用配置文件
- 优先使用外部配置文件
#db.properties
mysql_driver=com.mysql.cj.jdbc.Driver
#不需要转义&
MyBatis_url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf-8
db_username=root
db_pwd=2017002231
Setting | Description | Valid Values | Default |
---|---|---|---|
cacheEnabled | 是否缓存Globally enables or disables any caches configured in any mapper under this configuration. | true | false | true |
lazyLoadingEnabled | 懒加载,提高开发效率When enabled, all relations will be lazily loaded. This value can be superseded for a specific relation by using the fetchType attribute on it. |
true | false | false |
mapUnderscoreToCamelCase | Enables automatic mapping from classic database column names A_COLUMN to camel case classic Java property names aColumn. | true | false | false |
logImpl | MyBatis的日志实现方式Specifies which logging implementation MyBatis should use. | LOG4J|STDOUT_LOGGING | No Set |
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
settings>
导入 LOG4J
包
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
配置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 = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
# 文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File = ./logs/log.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold = DEBUG
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %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
导包
import org.apache.log4j.Logger;
设置变量
static Logger logger = Logger.getLogger(UserMapperTest.class);
Logger.getLogger(className):将日志对象与目标对象绑定
使用
log级别
MyBatis 可以配置成适应多种环境,但每个 SqlSessionFactory 实例只能选择一种环境
如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。
两种类型的事务管理器(也就是 type=“[JDBC|MANAGED]”)
连接数据库:
三种数据源类型
UNPOOLED——用完即销毁
无连接池,每次请求时打开和关闭连接
浪费资源
POOLED——用完即回收
JNDI
用于减少完全限定名的冗余给Bean取别名
实体类较少,可逐一指定
<typeAliases>
<typeAlias type="com.kuang.pojo.User" alias="User"/>
typeAliases>
<mapper namespace="com.kuang.mapper.UserMapper">
<select id="getUserList" resultType="User">
select *from mybatis.user;
select>
mapper>
You can also specify a package where MyBatis will search for all beans.包中实体类的别名为 lowercase(类名的首字母)
<typeAliases>
<package name="com.kuang.pojo" />
typeAliases>
<mapper namespace="com.kuang.mapper.UserMapper">
<select id="getUserList" resultType="user">
select *from mybatis.user;
select>
mapper>
If the @Alias
annotation is found its value will be used as an alias. 优先级 :注解别名>配置别名
Alias | Mapped Type |
---|---|
_普通数据类型 |
普通数据类型(int,short,long,byte,double,float,boolean) |
小写首字母(数据类型名) | 首字母大写的数据类型(基本数据类型 + Date,Object,Map,HashMap,List,ArrayList,Collection,Iterator) |
Integer,int | BigDecimal |
decimal,bigdecimal | Integer |
接口实现(mapper.xml)必须在configuration中注册才可被发现
第一种方式:资源路径【推荐】
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
mappers>
第二种方式:类名
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
mappers>
第三种方式:包内全导入
<mappers>
<package name="org.mybatis.builder"/>
mappers>
第二、三种方式的问题
resultMap
– The most complicated and powerful element that describes how to load your objects from the database result sets.
insert
– A mapped INSERT statement.update
– A mapped UPDATE statement.delete
– A mapped DELETE statement.select
– A mapped SELECT statement.简单的例子
public class User {
private Integer id;
private String user_name;
private String password;
}
在 sql
中,用 as
关键字,可以给某一字段起别名
select *from user where id=#{id}
select
id as id,
user_name as user_name,
pwd as password
from user where id=#{id};
在 Mybatis
中,使用 ResultMap
做结果映射,只需要将有差异的属性与字段映射即可
关联association:多对一
集合collection:一对多
create table teacher(
id int(10) not null,
user_name varchar(30) default null,
primary key(id)
)engine=InnoDB default charset=utf8;
insert into teacher(id,user_name) values(1,'秦老师');
insert into teacher(id,user_name) values(2,'江老师');
create table student(
id int(10) not null,
user_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,user_name,tid) values(1,"小明",1);
insert into student(id,user_name,tid) values(2,"小红",2);
insert into student(id,user_name,tid) values(3,"小张",1);
insert into student(id,user_name,tid) values(4,"小李",1);
insert into student(id,user_name,tid) values(5,"小王",2);
select s.id as sid,s.user_name as sname,t.id as tid,t.user_name as tname
from student as s,teacher as t
where s.tid=t.id
接口
List<Student> getStudent2();
接口实现
<select id="getStudent2" resultMap="StudentTeacher2">
select s.id as sid,s.user_name as sname,t.id as tid,t.user_name as tname
from student as s,teacher as t
where s.tid=t.id
select>
<resultMap id="StudentTeacher2" type="student">
<result property="id" column="sid"/>
<result property="user_name" column="sname"/>
<association property="teacher" javaType="teacher">
<result property="id" column="tid"/>
<result property="user_name" column="tname"/>
association>
resultMap>
测试
select *
from student as s
where s.tid
in (select t.id from teacher as t);
定义接口
//查询学生对应的老师信息
List<Student> getStudent();
实现接口
<select id="getStudent" resultMap="StudentTeacher">
select *from mybatis.student;
select>
<resultMap id="StudentTeacher" type="student">
<association property="teacher" column="tid" javaType="teacher" select="getTeacher"/>
resultMap>
<select id="getTeacher" resultType="teacher">
select *from mybatis.teacher where id=#{tid};
select>
@Data
public class Student {
private Integer id;
private String user_name;
private Integer tid;
}
@Data
public class Teacher {
private Integer id;
private String user_name;
//一个老师拥有多个学生
private List<Student> students;
}
实现根据teacher.id查找该老师对应的所有学生
select t.id tid,t.user_name tname, s.id sid,s.user_name sname
from teacher t,student s
where t.id=s.tid and t.id=1;
定义接口
//获取某个老师下所有的学生信息
Teacher getTeacherById(@Param("tid") Integer id);
实现接口
<select id="getTeacherById" resultMap="StudentTeacher">
select t.id tid,t.user_name tname, s.id sid,s.user_name sname
from teacher t,student s
where t.id=s.tid and t.id=#{tid};
select>
<resultMap id="StudentTeacher" type="Teacher">
<result property="id" column="tid"/>
<result property="user_name" column="tname"/>
<collection property="students" ofType="student">
<result property="id" column="sid"/>
<result property="user_name" column="sname"/>
<result property="tid" column="tid"/>
collection>
resultMap>
测试
select tid,(select user_name from teacher where id=1) tname,id sid,user_name sname
from student s
where tid=1;
定义接口
Teacher getTeacherById2(@Param("tid") Integer id);
实现接口
<select id="getTeacherById2" resultMap="StudentTeacher2">
select *from mybatis.teacher where id=#{tid}
select>
<resultMap id="StudentTeacher2" type="teacher">
<collection property="students" column="id" javaType="ArrayList" ofType="student" select="GetStudentByTid" />
resultMap>
<select id="GetStudentByTid" resultType="student">
select *
from mybatis.student
where tid=#{tid};
select>
测试
根据不同的条件生成不同的sql语句
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;
@Data
public class Blog {
private String id;
private String title;
private String author;
private Date createTime;
private Integer views;
}
@SuppressWarnings("all")//抑制所有警告
public class TestBlog {
@Test
public void test(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
Blog blog = new Blog();
blog.setId(IDUtil.getId());
blog.setAuthor("kuang");
blog.setTitle("MyBatis如此简单!");
blog.setCreateTime(new Date());
blog.setViews(9999);
mapper.insert(blog);
blog.setId(IDUtil.getId());
blog.setTitle("Java如此简单!");
blog.setViews(9999);
mapper.insert(blog);
blog.setId(IDUtil.getId());
blog.setTitle("Spring如此简单!");
mapper.insert(blog);
blog.setId(IDUtil.getId());
blog.setTitle("微服务如此简单!");
mapper.insert(blog);
sqlSession.close();
}
}
接口
//查询blog信息
List<Blog> queryBlogIF(Map map);
接口实现
<select id="queryBlogIF" resultType="blog" parameterType="map">
select *from mybatis.blog where 1=1
<if test="title!= null">
and titie=#{title}
if>
<if test="author!= null">
and author = #{author}
if>
select>
测试
<select id="queryBlogIF" resultType="blog" parameterType="map">
select *from mybatis.blog
<where>
<if test="title!= null">
title=#{title}
if>
<if test="author!= null">
and author = #{author}
if>
where>
select>
switch-case-default | if-else if - else
定义接口
List<Blog> queryBlogIF1(Map map);
实现接口
<select id="queryBlogIF1" parameterType="map" resultType="blog">
select *from mybatis.blog
<where>
<choose>
<when test="id!=null">
id=#{id}
when>
<when test="title != null">
title=#{title}
when>
<when test="author != null">
author=#{author}
when>
<otherwise>
views>1000
otherwise>
choose>
where>
select>
测试
定义接口
//更新信息
int updateBlog(Map map);
实现接口
<update id="updateBlog" parameterType="map">
update mybatis.blog
<set>
<if test="title!=null">title=#{title},if>
<if test="author!=null">author=#{author},if>
<if test="views!=null">views=#{views},if>
create_time =#{createTime}
set>
where id=#{id}
update>
测试
前缀后缀都是 prefix,XXOverrides决定替换的位置
<select id="queryBlogIFByTrim" resultType="blog" parameterType="map">
select *from mybatis.blog
<trim prefix="where" prefixOverrides="and |or ">
<if test="title!= null">
title=#{title}
if>
<if test="author!= null">
and author = #{author}
if>
trim>
select>
...
公共部分抽取出来,方便复用
抽取
引用<sql id="if-title-author">
<if test="title!= null">
title=#{title}
if>
<if test="author!= null">
and author = #{author}
if>
sql>
<select id="queryBlogIFByTrim" resultType="blog" parameterType="map">
select *from mybatis.blog
<trim prefix="where" prefixOverrides="and |or ">
<include refid="if-title-author" />
trim>
select>
标签sql
in
的动态范围查询
select *from user where 1=1 and
(id=1 or id=2 or id=3);
<foreach item="item" collection="ids" open="(" separator=" or " close=")">
#{item}
foreach>
定义接口
List<Blog> queryBlogIn(Map map);
实现接口
<select id="queryBlogIn" parameterType="map" resultType="blog">
select *from mybatis.blog
<where>
<foreach collection="ids" item="id" open="(" separator="or" close=")">
id=#{id}
foreach>
where>
select>
测试
select *from [table_name] limit [offset],[limit];
# [offset]缺省,默认从0开始,到[end]
select *from [table_name] limit [end];
接口
//分页查询用户信息
List<User> getUserWithLimit(Map<String,Integer> map);
接口配置
<select id="getUserWithLimit" resultMap="UserMap" resultType="user" parameterType="map">
select *from mybatis.user limit #{offset},#{limit};
select>
测试
@Test
public void testGetUserWithLimit(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("offset",1);
map.put("limit",2);
List<User> userList = mapper.getUserWithLimit(map);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
不在sql进行分页,通过sqlSession对象实现分页——RowBounds
接口
List<User> getUserWithLimit2();
配置Mapper
<select id="getUserWithLimit2" resultMap="UserMap" resultType="user">
select *from mybatis.user;
</select>
测试
@Test
public void testGetUserWithLimit2(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
RowBounds rowbounds = new RowBounds(1,2);
List<User> userList = sqlSession.selectList("com.kuang.mapper.UserMapper.getUserWithLimit2",null,rowbounds);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
问题:连接数据库消耗资源
解决:一次查询,保存到高速存储——> 内存
缓存:
使用缓存,减少与数据库交互次数,减少系统开销,提高系统效率
系统默认定义两级缓存:一级缓存和二级缓存
一级缓存默认开启,在一次SESSION期间有效
开启日志
测试一个Session中查询两次相同记录
@Test
public void test(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user1 = mapper.getUserById(1);
System.out.println(user1);
System.out.println("====================");
User user2 = mapper.getUserById(1);
System.out.println(user2);
System.out.println(user1==user2);
sqlSession.close();
}
查看日志输出
两次查找一次查表
两次结果引用同一对象
工作机制:
一个Session期间的数据会被放到一级缓存,当Session关闭或提交,对应的一级缓存中的数据被保存到二级缓存中
- 新的Session查询信息,从二级缓存中获取内容
- 不同的mapper查出的数据会放到自己对应的缓存中
mybatis-config.xml 开启二级缓存
<setting name="cacheEnabled" value="true"/>
配置mapper.xml
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
LRU
:默认FIFO
测试
问题
java.io.NotSerializableException: com.kuang.pojo.User
package com.kuang.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
private Integer id;
private String user_name;
private String pwd;
}
查找顺序:
@Test
public void test(){
SqlSession sqlSession1 = MyBatisUtils.getSqlSession();
User user1 = sqlSession1.getMapper(UserMapper.class).getUserById(1);
System.out.println(user1);
sqlSession1.close();
SqlSession sqlSession2 = MyBatisUtils.getSqlSession();
User user2 = sqlSession2.getMapper(UserMapper.class).getUserById(1);
System.out.println(user2);
sqlSession2.close();
System.out.println(user1==user2);
SqlSession sqlSession3 = MyBatisUtils.getSqlSession();
User user3 = sqlSession3.getMapper(UserMapper.class).getUserById(2);
System.out.println(user3);
sqlSession3.close();
}
开源Java分布式缓存
<dependency>
<groupId>org.mybatis.cachesgroupId>
<artifactId>mybatis-ehcacheartifactId>
<version>1.1.0version>
dependency>
<cache type="com.domain.something.MyCustomCache"/>
public interface Cache {
String getId();
int getSize();
void putObject(Object key, Object value);
Object getObject(Object key);
boolean hasKey(Object key);
Object removeObject(Object key);
void clear();
}
目的:解耦
本质:反射机制
底层:动态代理
Java Annotations are both limited and messier for more complicated statements.
注解在接口上实现
public interface UserMapper {
@Select("select *from user")
List<User> getUsers();
}
绑定接口
<mappers>
<mapper class="com.kuang.mapper.UserMapper"/>
mappers>
测试
@Test
public void test(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> users = mapper.getUsers();
for (User user : users) {
System.out.println(user);
}
sqlSession.close();
}
当有多个参数,基本数据类型或String
的参数前加注解 @param
关联参数
引用类型不需要加
sql中使用的是@Param()中设定的属性名
public class MyBatisUtils{
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession(true);
}
}
//UserMapper.java
public interface UserMapper{
@Insert("insert into user(id,user_name,pwd) values(#{id},#{user_name},#{pwd})")
int insertUser(User user);
}
//UserMapper.java
public interface UserMapper{
@Update("update user set user_name=#{user_name},pwd=#{pwd} where id=#{id}")
int updateUser(User user);
}
IDEA中安装插件
项目中导入依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
使用注解简化
@Getter and @Setter
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
在MyBatis基础上,只做增强不做改变,为简化开发、提高效率而生
通过简单语句,生成SQL语句,交给MyBatis执行
创建数据库 haoke
use haoke;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`name` varchar(30) DEFAULT NULL COMMENT '姓名',
`age` int(11) DEFAULT NULL COMMENT '年龄',
`email` varchar(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- 插入数据
INSERT INTO `user` (`id`, `name`, `age`, `email`) VALUES ('1', 'Jone', '18','test1@baomidou.com');
INSERT INTO `user` (`id`, `name`, `age`, `email`) VALUES ('2', 'Jack', '20','test2@baomidou.com');
INSERT INTO `user` (`id`, `name`, `age`, `email`) VALUES ('3', 'Tom', '28','test3@baomidou.com');
INSERT INTO `user` (`id`, `name`, `age`, `email`) VALUES ('4', 'Sandy', '21','test4@baomidou.com');
INSERT INTO `user` (`id`, `name`, `age`, `email`) VALUES ('5', 'Billie', '24','test5@baomidou.com');
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.4.3version>
parent>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.4.2version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.16version>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
spring.application.name = mybatis-plus
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://8.140.130.91:3306/haoke?characterEncoding=utf8&useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
package com.mybatisplus.pojo;
public class User {
private Long id;
private String name;
private Integer age;
private String email;
public User() {
}
public User(Long id, String name, Integer age, String email) {
this.id = id;
this.name = name;
this.age = age;
this.email = email;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
package com.mybatisplus.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface UserMapper extends BaseMapper<User> {
}
package com.mybatisplus;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("com.mybatisplus.mapper") //设置mapper接口的扫描包
@SpringBootApplication
public class Myapplication {
public static void main(String[] args) {
SpringApplication.run(Myapplication.class,args);
}
}
package com.mybatisplus;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("com.mybatisplus.mapper") //设置mapper接口的扫描包
@SpringBootApplication
public class Myapplication {
public static void main(String[] args) {
SpringApplication.run(Myapplication.class,args);
}
}
package com.mybatisplus;
import com.mybatisplus.mapper.UserMapper;
import com.mybatisplus.pojo.User;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void test(){
System.out.println("-------selectAll method test-------");
List<User> users = userMapper.selectList(null);
for (User user : users) {
System.out.println(user);
}
}
}
在MybatisPlus中,BaseMapper中定义了一些常用的CRUD方法,当我们自定义的Mapper接口继承BaseMapper后即可拥有了这些方法 【这些方法仅适合单表操作】
/**
* Mapper 继承该接口后,无需编写 mapper.xml 文件,即可获得CRUD功能
*/
public interface BaseMapper<T> extends Mapper<T> {
/**
* 插入一条记录
*
* @param entity 实体对象
*/
int insert(T entity);
/**
* 根据 ID 删除
*
* @param id 主键ID
*/
int deleteById(Serializable id);
/**
* 根据 columnMap 条件,删除记录
*
* @param columnMap 表字段 map 对象
*/
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
/**
* 根据 entity 条件,删除记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
*/
int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 删除(根据ID 批量删除)
*
* @param idList 主键ID列表(不能为 null 以及 empty)
*/
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
/**
* 根据 ID 修改
*
* @param entity 实体对象
*/
int updateById(@Param(Constants.ENTITY) T entity);
/**
* 根据 whereEntity 条件,更新记录
*
* @param entity 实体对象 (set 条件值,可以为 null)
* @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
*/
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
/**
* 根据 ID 查询
*
* @param id 主键ID
*/
T selectById(Serializable id);
/**
* 查询(根据ID 批量查询)
*
* @param idList 主键ID列表(不能为 null 以及 empty)
*/
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
/**
* 查询(根据 columnMap 条件)
*
* @param columnMap 表字段 map 对象
*/
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
/**
* 根据 entity 条件,查询一条记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 Wrapper 条件,查询总记录数
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 entity 条件,查询全部记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 Wrapper 条件,查询全部记录
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 Wrapper 条件,查询全部记录
* 注意: 只返回第一个字段的值
*
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 entity 条件,查询全部记录(并翻页)
*
* @param page 分页查询条件(可以为 RowBounds.DEFAULT)
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
<E extends IPage<T>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
/**
* 根据 Wrapper 条件,查询全部记录(并翻页)
*
* @param page 分页查询条件
* @param queryWrapper 实体对象封装操作类
*/
<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
}
@Test
public void testSelectById(){
System.out.println("通过Id查询");
User user = userMapper.selectById(3L);//数据类型为Long,id为3
System.out.println(user);
}
https://mp.baomidou.com/guide/wrapper.html#abstractwrapper
@Test
public void testSave(){
User user = new User();
user.setAge(25);
user.setEmail("[email protected]");
user.setName("zhangsan");
int count = userMapper.insert(user);
System.out.println("新增数据成功! count=>"+count);
}
所以自增问题出现在java参数传递中
public class User {
@TableId(value = "ID", type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
private String email;
}
根据id修改,只修改指定的字段
/**
* 分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
// paginationInterceptor.setLimit(500);
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
paginationInnerInterceptor.setDbType(DbType.MYSQL);
interceptor.addInnerInterceptor(paginationInnerInterceptor);
return interceptor;
}
使用MyBatis原生配置文件
# 指定全局配置文件
mybatis-plus.config-location = classpath:mybatis-config.xml
# 指定mapper.xml文件
mybatis-plus.mapper-locations = classpath*:mybatis/*.xml
若指定配置文件,无需配置环境,只需要
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
configuration>
https://mp.baomidou.com/guide/config.html#%E5%9F%BA%E6%9C%AC%E9%85%8D%E7%BD%AE