熬过无人问津的日子才会有诗和远方。
什么是框架?
三层架构和SSM框架的关系
三层架构:数据访问层、业务逻辑层和表示层(web层),区分层次的目的即为了高内聚低耦合的思想。在软件体系架构设计中,分层式结构是最常见,也是最重要的一种结构。
MVC:模型(model)、视图(view)、控制器(controller。
SSM:Spring Framework、Spring MVC、MyBatis(扩展MyBatis-Plus)。
SSH:Spring、Struts、Hibernate(扩展JPA)。
JavaSE => JDBC => Servlet+JSP => SSM =>SpringBoot(分布式) => SpringCould(微服务)
MyBatis缺点
软件设计:(open-close开闭原则)尽量不修改源代码,对程序进行扩展。
如何使用MyBatis?
1、使用 MyBatis, 只需将 mybatis-x.x.x.jar
文件置于类路径(classpath)中即可。
2、如果使用 Maven 来构建项目,则需将下面的依赖引入 pom.xml 文件中:
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>x.x.xversion>
dependency>
通过本节可以初步了解MyBatis的使用以及logback的配置
1、创建一个普通的Maven项目
2、引入依赖坐标
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.5version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.46version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.20version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.2.3version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-coreartifactId>
<version>1.2.3version>
dependency>
3、导入SQL脚本
-- 创建数据库
drop database if exists `mybatis`;
create database `mybatis` character set = utf8;
use mybatis;
-- 创建数据表
create table `user`(
`id` int auto_increment primary key comment '编号',
`name` varchar(20) unique comment '姓名', -- 唯一约束
`pwd` varchar(20) comment '密码',
`gender` char(1) comment '性别',
`addr` varchar(30) comment '家庭住址'
)engine=innodb default charset=utf8;
-- 插入数据
insert into user(name,pwd,gender,addr) values
("张三","123456",'男',"北京"),
("李四","123456",'女',"南京"),
("王五","777777",'男',"杭州"),
("赵六","123456",'女',"温州"),
("陈七","666666",'男',"黑河");
4、编写实体类
package com.baidou.pojo;
/**
* 用户实体类
*
* @author 白豆五
* @version 2022/11/30 11:07
* @since JDK8
*/
public class User {
private Integer id; // 编号
private String name; // 姓名
private String pwd; // 密码
private char gender; // 性别
private String addr; // 家庭住址
// 满参构造方法
public User(Integer id, String name, String pwd, char gender, String addr) {
this.id = id;
this.name = name;
this.pwd = pwd;
this.gender = gender;
this.addr = addr;
}
// 无参构造方法
public User() {
}
// set/get方法
public Integer getId() {
return id;
}
public void setId(Integer 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;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
// 重写Object类的toString方法,返回对象里的内容
// Object类的toString方法返回的是对象的地址值,即: "类的全限定名@十六进制的哈希码"
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
", gender=" + gender +
", addr='" + addr + '\'' +
'}';
}
}
5、编写mapper接口
package com.baidou.mapper;
import com.baidou.pojo.User;
import java.util.List;
/**
* 基于MyBatis实现用户接口
* mapper、dao都是对数据库进行持久化操作的(crud)
*/
public interface UserMapper {
// 查询所有用户
List<User> selectAll();
}
6、编写UserMapper.xml(SQL映射文件)
参考MyBatis官网的入门案例:https://mybatis.org/mybatis-3/zh/getting-started.html
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.baidou.mapper.UserMapper">
<select id="selectAll" resultType="com.baidou.pojo.User">
select * from user
select>
mapper>
7、编写MyBatis核心配置文件
参考MyBatis官网的入门案例:https://mybatis.org/mybatis-3/zh/getting-started.html
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.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/baidou/mapper/UserMapper.xml"/>
mappers>
configuration>
8、编写logback.xml日志配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!-- 配置文件修改时重新加载,默认true -->
<configuration scan="true">
<!--控制台输出-->
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!-- 输出的日志格式 -->
<pattern>[%level] %blue(%d{HH:mm:ss.SSS}) %cyan([%thread]) %boldGreen(%logger{15}) - %msg%n</pattern>
</encoder>
</appender>
<!--level:用来设置日志输出级别,有OFF FATAL ERROR WARN INFO DEBUG TRACE ALL,默认DEBUG-->
<logger name="com.baidou" level="DEBUG" additivity="false">
<appender-ref ref="Console"/>
</logger>
<root level="DEBUG">
<appender-ref ref="Console"/>
</root>
</configuration>
9、编写测试
import com.baidou.mapper.UserMapper;
import com.baidou.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* mybatis快速入门
* @author 白豆五
* @version 2022/11/30 12:55
* @since JDK8
*/
public class MyTest {
/**
* 方式一: 使用qlSession.selectList()查询所有用户(旧版mybatis的API,不推荐使用)
* @throws IOException
*/
@Test
public void test1() throws IOException {
// 1、加载mybatis核心配置文件,获取SqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream is = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
// 2、获取对应的SqlSession对象,用来执行sql语句
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3、执行sql语句, selectList()方法的参数是一个字符串,该字符串必须是映射配置文件的 namespace.id
List<User> list = sqlSession.selectList("com.baidou.mapper.UserMapper.selectAll");
// 输出结果
for (User user :
list) {
System.out.println(user);
}
// 4、释放资源
sqlSession.close();
}
/**
* 使用Mapper代理开发,查询所有用户
* @throws IOException
*/
@Test
public void test2() throws IOException {
// 1、加载Mybatis核心配置文件,获取SqlSessionFactory对象
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2、获取对应的SqlSession对象,用来执行sql语句
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3、获取mapper,来调用mapper中的方法
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> users = mapper.selectAll();
users.forEach(System.out::println);
// 4、关闭SqlSession
sqlSession.close();
}
}
sqlSession.selectList()
,属于方法的调用(mybatis旧版的api),需要传入映射文件的名称空间和查询语句的id(即 "namespace.id"
),然后它每次返回的类型都是Object,会存在类型转换问题,导致不太安全。sqlSession.getMapper()
,更灵活的使用方法,不依赖上述的字符串字面值而且安全,只需传参UserMapper.class
,返回的是mapper
接口的代理对象,然后通过mapper调用对应方法完成sql的执行。MyBatis执行流程:
MyBatis核心配置文件:mybatis-config.xml
MyBatis映射配置文件:XxxMapper.xml
后期在使用MyBatis框架做数据库操作(持久化操作)会经常使用这两个配置文件。
当然我们也可以在这个XML的dtd约束文件中查看相应的配置:
核心配置文件(mybatis-config.xml)的层级结构如下:
注:配置每个标签时,需要遵守前后顺序!
configuration表示核心配置文件的根标签。
1、编写db.properties配置文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf-8
username=root
password=123456
2、在mybatis-config.xml中引用db.properties
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.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.baidou.mapper"/>
mappers>
configuration>
在公司做项目的时候,如果开发阶段连接开发环境的数据库,那么数据库的配置要管运维或者DBA的同事要。
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写;
使用场景:1、给实体类起别名(跟map挺像,K-V键值对)
<typeAliases>
<typeAlias type="com.baidou.pojo.User" alias="user"/>
typeAliases>
使用场景:2、扫描实体类的包,它的的默认别名为类名,首字母小写
<typeAliases>
<package name="com.baidou.pojo"/>
typeAliases>
在实体类比较少的时候使用第一种方式,如果实体类比较多建议使用第二种方式!
区别:第一种可以自定义别名,第二种它就不行(如果非要改 需要在实体类上增加@Alias注解)。
下面是一些为常见的 Java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。
别名 | 映射的类型 |
---|---|
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
object | Object |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
在MyBatis全局配置文件中通过
标签控制MyBatis全局开关。
MyBatis的设置:https://mybatis.org/mybatis-3/zh/configuration.html#settings
示例:在mybatis-config.xml配置日志输出
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
settings>
mappers(映射器)的作用是告诉 MyBatis 到哪里去找映射文件;
使用场景:1. 使用相对于类路径的资源引用(推荐使用)
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
mappers>
使用场景:2. 使用映射器接口实现类绑定注册
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
mappers>
使用场景:3. 使用包扫描进行注入绑定
<mappers>
<package name="org.mybatis.builder"/>
mappers>
注:接口和它的配置文件必须同名,接口和它的映射文件必须在同级包下(SQL映射文件可以放在src目录中,也可以放在resources目录中 );
MyBatis 真正强大之处在于它的语句映射,这是它的魔力所在。由于它的功能强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 致力于减少使用成本,让用户能更专注于写SQL代码。
SQL 映射配置文件标签结构如下:
mapper
– 作为映射配置文件的根标签,namespace属性值就是绑定mapper接口的全限定名(包名.接口名)。
cache
– 该命名空间的缓存配置。cache-ref
– 引用其它命名空间的缓存配置。resultMap
– 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。parameterMap
– 老式风格的参数映射。此元素已被废弃,并可能在将来被移除!请使用行内参数映射。文档中不会介绍此元素。sql
– 可被其它语句引用的可重用语句块。select
– 映射查询语句,resultType – SQL语句执行的返回值;parameterType – 参数类型;insert
– 映射插入语句。update
– 映射更新语句。delete
– 映射删除语句。在mapper接口中定义方法,方法名就是该SQL映射文件中sql语句的id,并保持参数类型和返回值类型一致;
使用MyBatis针对User表实现增删改查操作以及工具类的使用。
前期准备:配置数据库资源文件db.properties以及MyBatis核心配置文件。
sql脚本:
-- 创建数据库
drop database if exists `mybatis`;
create database `mybatis` character set = utf8;
use mybatis;
-- 创建数据表
create table `user`(
`id` int auto_increment primary key comment '编号',
`name` varchar(20) unique comment '姓名', -- 唯一约束
`pwd` varchar(20) comment '密码',
`gender` char(1) comment '性别',
`addr` varchar(30) comment '家庭住址'
)engine=innodb default charset=utf8;
-- 插入数据
insert into user(name,pwd,gender,addr) values
("张三","123456",'男',"北京"),
("李四","123456",'女',"南京"),
("王五","777777",'男',"杭州"),
("赵六","123456",'女',"温州"),
("陈七","666666",'男',"黑河");
db.properties:
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=false&useUnicode=true&acharacterEncoding=UTF-8
db.username=root
db.password=123456
mybatis-config.xml:
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.properties"/>
<typeAliases>
<package name="com.baidou.pojo"/>
typeAliases>
<environments default="dev">
<environment id="dev">
<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.baidou.mapper"/>
mappers>
configuration>
1、编写实体类
package com.baidou.pojo;
/**
* 用户实体类
*
* @author 白豆五
* @version 2022/11/30 11:07
* @since JDK8
*/
public class User {
private Integer id; // 编号
private String name; // 姓名
private String pwd; // 密码
private char gender; // 性别
private String addr; // 家庭住址
// 满参构造方法
public User(Integer id, String name, String pwd, char gender, String addr) {
this.id = id;
this.name = name;
this.pwd = pwd;
this.gender = gender;
this.addr = addr;
}
// 无参构造方法
public User() {
}
// set/get方法
public Integer getId() {
return id;
}
public void setId(Integer 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;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
// 重写toString方法
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
", gender=" + gender +
", addr='" + addr + '\'' +
'}';
}
}
2、编写接口:
package com.baidou.mapper;
import com.baidou.pojo.User;
import java.util.List;
/**
* 基于MyBatis实现用户接口
*
*/
public interface UserMapper {
// 根据id查询用户信息
User findUserById(int id);
}
3、编写mapper映射文件:
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.baidou.mapper.UserMapper">
<select id="findUserById" resultType="com.baidou.pojo.User">
select * from user where id =#{id}
select>
mapper>
#{}
表示占位符,可以看做JDBC中PreparedStatement的?
占位符。(预处理)package com.baidou.mapper;
import com.baidou.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
/**
* 测试类
*
* @author 白豆五
* @version 2022/12/1 20:51
* @since JDK8
*/
public class UserMapperTest {
@Test
public void testFindUserById() throws IOException {
// 加载Mybatis核心配置文件,获取SqlSessionFactory对象
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 通过sqlSession工厂构建SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取接口的mapper代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 调用mapper中的方法,执行sql语句
User user = mapper.findUserById(1);
System.out.println(user);
// 关闭SqlSession
sqlSession.close();
}
}
编写接口:
// 添加用户
int addUser(User user);
编写mapper映射文件:
<!-- 添加用户-->
<insert id="addUser" parameterType="user">
insert into mybatis.user(name, pwd, gender, addr) values(#{name}, #{pwd}, #{gender}, #{addr});
</insert>
编写测试:
@Test
public void testaddUser() throws IOException {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = new User();
user.setName("水火");
user.setAddr("洛杉矶");
user.setGender('男');
user.setPwd("shuihuo123");
int count = mapper.addUser(user);
sqlSession.commit();
if (count > 0) {
System.out.println("添加成功");
}
sqlSession.close();
}
因为我们配置主键是自动增加的,也就是不给主键穿值,当同时插入两张表的时候会出现问题,装进对象的时候id为null,通过如下配置解决这个问题。
在 insert 标签上添加如下属性:
编写接口:
// 修改用户
int updateUser(User user);
编写mapper映射文件:
<!--修改用户-->
<update id="updateUser" parameterType="user">
update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id}
</update>
编写测试:
@Test
public void testUpdateUser() throws IOException {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = new User();
user.setId(6);
user.setName("葛小伦");
user.setPwd("gexiaolun");
int count = mapper.updateUser(user);
sqlSession.commit();
if (count > 0) {
System.out.println("修改成功");
}
sqlSession.close();
}
编写接口:
// 通过id删除用户
int deleteUserById(int id);
编写mapper映射文件:
<delete id="deleteUserById">
delete from user where id=#{id}
delete>
编写测试:
@Test
public void testDeleteUserById() throws IOException {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int count = mapper.deleteUserById(6);
sqlSession.commit();
if (count > 0) {
System.out.println("删除成功");
}
sqlSession.close();
}
注意:增删改需要提交事务。(mybatis默认把自动提交事务改成手动提交,可以在sqlsession.open(true)开启自动提交事务,他这个方法不传参默认是手动提交,但是不推荐直接传参,手动根据场景使用比较灵活)
package com.baidou.util;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
/**
* MyBatisUtils工具类
*
* @author 白豆五
* @version 2022/12/1 21:32
* @since JDK8
*/
public class MyBatisUtils {
private static SqlSessionFactory sqlSessionFactory;
// 加载mybaits核心配置文件,获取SqlSessionFactory对象
static {
InputStream is = null;
try {
is = Resources.getResourceAsStream("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private MyBatisUtils() {
}
/**
* 获取SqlSession对象
*
* @return SqlSession
*/
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession();
}
/**
* 提交事务并释放sqlSession
*
* @param sqlSession
*/
public static void commitAndClose(SqlSession sqlSession) {
if (sqlSession != null) {
sqlSession.commit(); //提交事务
sqlSession.close();
}
}
/**
* 回滚事务并释放sqlSession
*
* @param sqlSession
*/
public static void rollbackAndClose(SqlSession sqlSession) {
if (sqlSession != null) {
sqlSession.rollback(); //回滚事务
sqlSession.close();
}
}
}
编写接口:
// 模糊查询
List<User> getUserLike(String name);
编写mapper映射文件:
<!-- 模糊查询 -->
<select id="getUserLike" resultType="user" parameterType="string">
select * from user where name like #{value}
</select>
方式一:在Java代码执行的时候,传递通配符 % 内容 %。
方式二:在SQL拼接中使用通配符。
参考文章:https://www.cnblogs.com/suhaha/p/11794786.html
我们使用日志除了要收集一些错误信息,还要查看MyBatis执行SQL语句的执行流程以便于日后排错。
目前日志框架要么使用Logback,要么使用Log4j2.x,不会使用最早的Log4j了。
1、导入依赖坐标
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
2、在resources目录下创建一个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/mybatis.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
3、在mybatis核心配置文件上配置日志(在configuration标签的第二个位置)
4、测试:
扩展:配置标准日志输出
在mybatis-config.xml文件中配置STDOUT_LOGGING
为日志的实现。
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
settings>
测试:
#{}
时,会将 sql 中的 #{} 替换为 ?
号,然后调用 PreparedStatement 的 set 方法来赋值;分页有很多种实现方式:如Limit实现分页、RowBounds 分页、分页插件(PageHelper)等
不带条件查询的分页
编写接口:
/**
* 分页查询用户列表(没有条件)
* 使用Map传参(如 startIndex、pageSize)
*
* @param map
* @return
*/
List<User> getUserByLimit(Map<String, Integer> map);
编写mapper映射文件:
<select id="getUserByLimit" resultType="user" parameterType="map">
select *
from user
limit #{startIndex},#{pageSize}
select>
测试:
@Test
public void testSelectUserByLimit() {
Map<String, Integer> map = new HashMap<>();
Integer pageNo = 2; //码页
Integer pageSize = 3; //每页显示3条数据
Integer startIndex = (pageNo - 1) * pageSize; //分页查询的起始位置
map.put("startIndex",startIndex);
map.put("pageSize",pageSize);
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserByLimit(map);
userList.forEach(System.out::println);
}
MyBatis的参数指的就是Mapper接口中函数的参数,该Mapepr接口中函数的参数类型可以分为如下四种:
简单类型,例如Stirng、Long、int等等
POJO或者Map,例如 Student、HashMap
多个参数,例如 userName、passWord,(注解、map)(不推荐使用)
POJO包装类对象,例如 QueryVO
,T表示泛型类型,为了更加通用而设计,适应场景就是复杂查询。
如果方法中只有一个参数,然后以简单类型传参,那么在映射文件中parameterType的值就是简单类型的别名,在SQL语句中用 #{任意字符串}
引入简单类型的参数 。
// 根据ID查询用户
User findUserById(int id);
<select id="findUserById" resultType="user" parameterType="int">
select *
from user
where id = #{id}
select>
MyBatis常用的类型别名如下:
使用注解@Param 传递多个参数
// 用户登录
User login(@Param("name") String userName, @Param("pwd") String passWord);
<select id="login" resultType="user" >
select * from user where name=#{name} and pwd=#{pwd}
select>
@Test
public void testLogin() {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
String userName = "张三";
String passWord = "123456";
User user = mapper.login(userName, passWord);
System.out.println(user!=null?"登录成功":"登录失败");
sqlSession.close();
}
如果传递多个参数,在映射文件中直接调用参数名会出错误的,他会让你以param1,…,paramn或者 arg1…argn方式调用参数。
MyBatis为开发者提供了一个注解@Param
,使用它可以为参数起名字,在映射配置文件中不需要定义parameterType
属性,MyBatis它自动获取,从而提高代码的可读性,但是这会带来一个麻烦。如果SQL很复杂拥有的参数大于10个,则需要为接口处理多个参数名,那么使用起来就很不容易了,不过不必担心,MyBatis还提供传递JavaBean
的形式。
通常使用POJO(实体类)对象或者Map来封装多个参数,前者需要定义模板,后者不用插入指定的参数比较灵活。
方案一:将多个参数封装到pojo中,那么映射配置文件中parameterType的值就是POJO的全限定名(即 包名+类名)或者是别名,在SQL语句中使用 #{POJO属性名}
来引入参数。
// 添加用户
int addUser(User user);
// 修改用户
int updateUser(User user);
<insert id="addUser" parameterType="user">
insert into user(name, pwd, gender, addr) value (#{name}, #{pwd}, #{gender}, #{addr})
insert>
<update id="updateUser" parameterType="user">
update user
set name=#{name},
pwd=#{pwd}
where id = #{id}
update>
方案二:将多个参数封装到一个Map集合中(前提条件是这些参数没有对应的POJO),然后映射配置文件中parameterType的值设置为map,最后在SQL语句中使用 #{map的key}
来引入参数。
// 带条件的分页查询
List<User> getUserByPage(Map<String, Integer> map);
<select id="getUserByPage" resultType="user" parameterType="map">
select *
from user
<where>
<if test="pwd!=null">
and pwd = #{pwd}
if>
where>
limit #{startIndex},#{pageSize}
select>
@Test
public void testSelectUserByPage() {
Map<String, Integer> map = new HashMap<>();
Integer pageNo = 1; //码页
Integer pageSize = 3; //每页显示3条数据
Integer startIndex = (pageNo - 1) * pageSize; //分页查询的起始位置
map.put("startIndex",startIndex);
map.put("pageSize",pageSize);
map.put("pwd",123456); //筛选密码为123456的用户
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserByPage(map);
userList.forEach(System.out::println);
}
Map几乎适用所有场景,但是我们用得不多。原因有两个:首先,Map是一个键值对集合,使用者要通过阅读它的键,才能明白其作用;其次,使用Map不能限定其传递的数据类型,因此业务性质不强,可读性差,使用者要读懂代码才能知道需要传递什么参数给它,所以不推荐用这种方式传递多个参数。
POJO包装类对象,也就是在一个对象中嵌入了另一个对象和其他条件。(套娃操作)
需求:使用分页查询,查询性别为男的用户列表
1、封装POJO包装类
package com.baidou.vo;
import com.baidou.pojo.User;
/**
* 用户查询条件
*
* @author 白豆五
* @version 2022/12/1 23:02
* @since JDK8
*/
public class QueryVO {
//页码(当前页)
private Long pageNo;
// 每页显示的条数
private Long pageSize;
//偏移量
private Long offSet;
// 查询用户的条件
private User userCondition;
public Long getOffSet() {
return (pageNo - 1) * pageSize; //分页查询的起始位置
}
public Long getPageNo() {
return pageNo;
}
public void setPageNo(Long pageNo) {
this.pageNo = pageNo;
}
public Long getPageSize() {
return pageSize;
}
public void setPageSize(Long pageSize) {
this.pageSize = pageSize;
}
public User getUserCondition() {
return userCondition;
}
public void setUserCondition(User userCondition) {
this.userCondition = userCondition;
}
/*解决问题:
org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'gender' in 'class com.baidou.vo.QueryVO'
### Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'gender' in 'class com.baidou.vo.QueryVO'
*/
public char getGender() {
return userCondition.getGender();
}
}
2、定义UserMapper接口
// 分页查询用户列表(有条件)
List<User> getUserByQueryVO(QueryVO queryVO);
3、编写映射
<select id="getUserByQueryVO" resultType="user" parameterType="com.baidou.vo.QueryVO">
select *
from user
<where>
<if test="gender!=null">
and gender=#{userCondition.gender}
if>
where>
limit #{offSet},#{pageSize}
select>
4、测试
@Test
public void testGetUserByQueryVO() {
QueryVO queryVO = new QueryVO();
User userCondition = new User();
userCondition.setGender('男');
queryVO.setUserCondition(userCondition);
queryVO.setPageNo(1L); //设置当前页面
queryVO.setPageSize(3L); //每页显示3条数据
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userVoList = mapper.getUserByQueryVO(queryVO);
userVoList.forEach(System.out::println);
sqlSession.close();
}
我们学习MyBatis框架主要学习MyBatis的核心配置文件和MyBatis映射配置文件。
MyBatis参数、MyBatis结果集、MyBatis动态SQL这三节都是围绕MyBatis映射配置文件的。
MyBatis结果集就是MyBatis 执行查询的SQL语句时返回的结果集,该结果集有三种类型:
单行单列的值
单行多列的值(用对象封装)
多行多列的值 (用List集合封装)
需要在映射配置文件中配置这三种结果;也就是标签的 resultType、resultMap属性。
resultMap
可以解决字段与属性名不一致问题。(当然sql片段和取别名也可以、或者在核心配置文件中配置驼峰命名)
前期准备
1、sql脚本:
use mybatis;
-- 删除 brand表
drop table if exists brand;
-- 创建 brand表
create table brand
(
-- id 主键
id int primary key auto_increment,
-- 品牌名称
brand_name varchar(20),
-- 企业名称
company_name varchar(20),
-- 排序字段
ordered int,
-- 描述信息
description varchar(100),
-- 状态:0:禁用 1:启用
status int
);
-- 添加数据
insert into brand (brand_name, company_name, ordered, description, status)
values ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),
('华为', '华为技术有限公司', 100, '华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界', 1),
('小米', '小米科技有限公司', 50, 'are you ok', 1);
2、编写实体类:
package com.baidou.pojo;
/**
* 品牌实体类
*/
public class Brand {
private Integer id; //品牌编号
private String brandName; //品牌名称
private String companyName; //企业名称
private Integer ordered; //排序字段
private String description; //描述信息
private Integer status; //状态 0禁用 1启用
public Brand(Integer id, String brandNmae, String companyName, Integer ordered, String description, Integer status) {
this.id = id;
this.brandName = brandNmae;
this.companyName = companyName;
this.ordered = ordered;
this.description = description;
this.status = status;
}
public Brand() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getBrandName() {
return brandName;
}
public void setBrandName(String brandNmae) {
this.brandName = brandNmae;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public Integer getOrdered() {
return ordered;
}
public void setOrdered(Integer ordered) {
this.ordered = ordered;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
@Override
public String toString() {
return "Brand{" +
"id=" + id +
", brandNmae='" + brandName + '\'' +
", companyName='" + companyName + '\'' +
", ordered=" + ordered +
", description='" + description + '\'' +
", status=" + status +
'}';
}
}
BrandMapper接口:
package com.baidou.mapper;
// 基于mybatis操作品牌的接口
public interface BrandMapper {
}
编写mapper映射文件(BrandMapper.xml):
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.baidou.mapper.BrandMapper">
mapper>
mybatis核心配置文件 (mybatis-config.xml)
DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.properties"/>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
settings>
<environments default="dev">
<environment id="dev">
<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.baidou.mapper"/>
mappers>
configuration>
数据库资源文件 db.properties:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf-8
username=root
password=123456
如果查询结果是单行单列的值,那么映射配置文件中的resultType属性值就是Mapper接口的返回值。
编写接口:
// 统计品牌数量
Long brandTotalCount();
编写mapper映射文件:
<select id="brandTotalCount" resultType="long">
select count(*) from mybatis.brand;
select>
编写测试:
/**
* 测试类
*
* @author 白豆五
* @version 2022/12/1 23:35
* @since JDK8
*/
public class BrandMapperTest {
@Test
public void testBrandTotalCount() {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
Long count = mapper.brandTotalCount();
System.out.println(count);
sqlSession.close();
}
}
当查询结果是单行多列的值时,MyBatis针对查询结果集提供了两种封装方式:
1、封装成pojo对象。
2、封装成map 。(不建议使用map来处理查询结果是单行多列的值)
如果查询结果是单行多列的值,将结果集封装成pojo对象,配置文件中的resultType属性值就是pojo的全限定名(包名+类名)或者是别名;此时它就要求查询结果的字段、字段类型必须和pojo对象的属性名、属性类型保持一致。
编写接口:
//根据ID查询品牌信息
Brand selectBrandById(int id);
编写mapper映射文件:
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.baidou.mapper.BrandMapper">
<select id="brandTotalCount" resultType="long">
select count(*) from mybatis.brand;
select>
mapper>
编写测试:
@Test
public void testSelectBrandById() {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
Brand brand = mapper.selectBrandById(1);
System.out.println(brand);
sqlSession.close();
}
属性名和字段名不一致会导致返回结果集的部分字段映射不到实体类对象,即该属性会显示null。
解决字段名与属性名不一致问题,有如下4种解决方案:
<select id="selectBrandById" resultType="generator.pojo.Brand">
select id, brand_name as brandName, company_name as companyName, ordered, description, status from mybatis.brand where id=#{id}
select>
缺点:不够严谨和通用,如果多个查询需要都起别名。
方式二:sql片段
<sql id="brandSql">
id, brand_name as brandName, company_name as companyName, ordered, description, status
sql>
<select id="selectBrandById" resultType="generator.pojo.Brand">
select
<include refid="brandSql"/>
from mybatis.brand where id=#{id}
select>
方式三:resultMap结果集映射
<resultMap id="brandMap" type="com.baidou.pojo.Brand">
<result property="brandName" column="brand_name">result>
<result property="companyName" column="company_name">result>
resultMap>
<select id="selectBrandById" resultMap="brandMap">
select * from mybatis.brand where id=#{id}
select>
推荐使用resultMap处理这个问题(而且resultMap非常强大)。
如果查询结果是单行多列的值,将结果集封装成Map,映射配置文件的resultType属性值就是map,那么此时查询结果中的字段名就是map的key,字段值就是map的value。
//通过品牌名称查询品牌信息
Map<String,Object> selectBrandByName(String name);
<select id="selectBrandByName" resultType="java.util.Map">
select * from mybatis.brand where brand_name=#{name};
select>
@Test
public void testSelectBrandByName() throws IOException {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
Map<String, Object> map = mapper.selectBrandByName("三只松鼠");
System.out.println("根据品牌名称查询品牌的结果是"+map);
}
缺点:必须知道map的key,才能找到数据。
查询结果是多行多列的值,将多条数据存储到List中,映射配置文件的resultType
属性值就是pojo的全限定名或者是别名。(如果属性名与字段名不一致,可以使用resultMap)
//查询所有品牌
List<Brand> selectBrandAll();
<select id="selectBrandAll" resultType="com.baidou.pojo.Brand">
# 查询的字段(或列)起别名
select id, brand_name as brandName, company_name as companyName, ordered, description, status from brand
select>
@Test
public void testSelectUserAll() throws IOException {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
List<Brand> list = mapper.selectBrandAll();
for (Brand brand:
list){
System.out.println(brand);
}
}
动态 SQL 是 MyBatis 的强大特性之一。在 JDBC 或其它类似的框架中,我们通常需要手动拼接 SQL 语句。根据不同的条件拼接 SQL 语句是一件极其痛苦的工作。例如,拼接时要确保添加了必要的空格,还要注意去掉列表最后一个列名的逗号。而动态 SQL 恰好解决了这一问题,可以根据场景动态的构建查询。
动态 SQL 只有几个基本元素,与 JSTL 或 XML 文本处理器相似,十分简单明了,大量的判断都可以在 MyBatis 的映射 XML 文件里配置,以达到许多需要大量代码才能实现的功能(注解方式配置SQL可读性差)。
动态 SQL 减少了平时编写SQL代码的工作量,更体现了 MyBatis 的灵活性、高度可配置性和可维护性。
MyBatis 动态SQL 包括以下几种元素:
环境搭建
1、新建一个数据库表:blog
字段为:id、title、author、create_time、views。
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;
2、创建一个普通的maven工程
3、编写IDUtils工具类
public class IDUtils {
private IDUtils() {
}
/**
* 生成Id
* a58d257945e64ce4a7908411123eac66
*
* @return String
*/
public static String genId() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
}
4、编写实体类Blog
public class Blog {
private String id; //博客id
private String title; //博客标题
private String author; //博客作者
private Date createTime; //创建时间
private int views; //浏览量
public Blog(String id, String title, String author, Date createTime, int views) {
this.id = id;
this.title = title;
this.author = author;
this.createTime = createTime;
this.views = views;
}
public Blog() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public int getViews() {
return views;
}
public void setViews(int views) {
this.views = views;
}
@Override
public String toString() {
return "Blog{" +
"id='" + id + '\'' +
", title='" + title + '\'' +
", author='" + author + '\'' +
", createTime=" + createTime +
", views=" + views +
'}';
}
}
5、编写mapper接口以及xml映射文件
public interface BlogMapper {
//添加一个博客
int addBlog(Blog blog);
}
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.baidou.mapper.BlogMapper">
<insert id="addBlog" parameterType="com.baidou.pojo.Blog">
insert into mybatis.blog(id, title, author, create_time, views)
values (#{id}, #{title}, #{author}, #{createTime}, #{views});
insert>
mapper>
6、mybatis核心配置文件,下划线驼峰自动转换
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="logImpl" value="STDOUT_LOGGING"/>
settings>
<mappers>
<package name="com.baidou.mapper"/>
mappers>
7、初始化数据
public class Test {
public static void main(String[] args) {
SqlSession session = MyBatisUtils.getSqlSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = new Blog();
blog.setId(IDUtils.genId());
blog.setTitle("Go语言高级");
blog.setAuthor("KKK");
blog.setCreateTime(new Date());
blog.setViews(9999);
mapper.addBlog(blog);
session.commit();
blog.setId(IDUtils.genId());
blog.setTitle("Java快速入门");
blog.setAuthor("AAA");
blog.setCreateTime(new Date());
blog.setViews(2000);
mapper.addBlog(blog);
session.commit();
blog.setId(IDUtils.genId());
blog.setTitle("Spring快速入门");
blog.setAuthor("");
blog.setCreateTime(new Date());
blog.setViews(3000);
mapper.addBlog(blog);
session.commit();
blog.setId(IDUtils.genId());
blog.setTitle("微服务快速入门");
blog.setAuthor("");
blog.setCreateTime(new Date());
blog.setViews(5000);
mapper.addBlog(blog);
session.commit();
session.close();
}
}
if 标签:条件判断( test 属性:逻辑表达式)
test属性传的是入参的参数,不是数据表的字段
需求:使用动态SQL查询指定作者的博客列表,如果没有指定作者名称,那么就查询所有。
//通过作者名称获取博客列表
List<Blog> selectBlogListByAuthor(String name);
<select id="selectBlogListByAuthor" resultType="blog" parameterType="string">
select *from blog
# 当作者不为空使拼接条件where author=#{name}
<if test="author != null and author!=''">
where author=#{name}
if>
select>
@Test
public void testSelectBlogListByAuthor(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
List<Blog> blogList = mapper.selectBlogListByAuthor(null);
for (Blog blog : blogList) {
System.out.println(blog);
}
sqlSession.close();
}
多个条件判断:
//查询指定作者,访问量大于2000的博客列表
List<Blog> selectBlogListByAuthorAndViews(Blog blog);
<select id="selectBlogListByAuthorAndViews" resultType="blog" parameterType="blog">
select title, author, create_time, views from blog
# 使用1=1完成条件的过渡,不然sql会报错
where 1=1
<if test="author!=null">
and author=#{author}
if>
<if test="views!=null">
and views>#{views}
if>
select>
@Test
public void testSelectBlogListByAuthorAndViews(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
Blog blog = new Blog();
blog.setAuthor("KKK");
blog.setViews(2000);
List<Blog> blogList = mapper.selectBlogListByAuthorAndViews(blog);
for (Blog blog1 : blogList) {
System.out.println(blog1);
}
sqlSession.close();
}
where标签的作用:
1、可以在条件之前加上where标签。
2、可以去掉第一个条件的and(也省略了1=1的过渡)
需求:查询指定作者,访问量大于2000的博客列表(多条查询)
//查询指定作者,访问量大于2000的博客列表
List<Blog> selectBlogListByAuthorAndViews(Blog blog);
<select id="selectBlogListByAuthorAndViews" resultType="blog" parameterType="blog">
select title, author, create_time, views from blog
# where 1=1
<where>
<if test="author!=null and author!=''">
# and author=#{author}
author=#{author}
if>
<if test="views!=null">
and views>#{views}
if>
where>
select>
@Test
public void testSelectBlogListByAuthorAndViews(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
Blog blog = new Blog();
blog.setAuthor("kkk");
blog.setViews(2000);
List<Blog> blogList = mapper.selectBlogListByAuthorAndViews(blog);
for (Blog blog1 : blogList) {
System.out.println(blog1);
}
sqlSession.close();
}
单个条件(分支)的动态SQL。
需求:单条件动态查询博客列表。
编写接口:
// 单条件动态查询博客列表
List<Blog> selectConditionSingle(Blog blog);
编写sql映射文件:
<select id="selectConditionSingle" resultType="com.baidou.pojo.Blog">
select * from mybatis.blog
<where>
<choose>
<when test="author!=null and author!=''">
and author=#{author}
when>
<when test="title!=null and title!=''">
and title like #{title}
when>
choose>
where>
select>
编写测试:
public class Test {
public static void main(String[] args) {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
Blog blog = new Blog();
blog.setTitle("%Java%");
// blog.setAuthor("KKK");
List<Blog> list = mapper.selectConditionSingle(blog);
for (Blog b : list) {
System.out.println(b);
}
sqlSession.close();
}
}
foreach标签可以遍历集合。
需求:根据传入的id列表批量删除多个博客
//根据传入的id列表批量删除多个博客
int deleteByIds(List<String> ids);
<delete id="deleteByIds" parameterType="string">
# delete from blog where id in(?,?,?); 删除多个数据
delete from blog where id in
<foreach collection="list" item="id" separator="," open="(" close=")">
#{id}
foreach>
;
delete>
@Test
public void testDeleteByIds() {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
List<String> list = new ArrayList<>();
list.add("a63e183c920f4547aa17ef04555612ef");
list.add("acf126f6a08a474d8bf47c6575e48c18");
list.add("eeb1fd8ea29f4d16bf46d7b37be281eb");
int deleteRows = mapper.deleteByIds(list);
System.out.println("删除数据受影响的行数是:"+deleteRows);
MyBatisUtils.commitAndColse(sqlSession); // 提交事务并释放sqlsession
}
sql标签可以把公共(多个查询都会使用到)的SQL语句进行抽取,然后再使用include标签引入该SQL语句。
优点:就是易于维护,提高开发效率。
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.baidou.mapper.BlogMapper">
<select id="selectBlogListByAuthor" resultType="blog" parameterType="string">
select id, title, author, create_time, views from blog
<if test="author != null">
where author=#{name}
if>
select>
<select id="selectBlogListByAuthorAndViews" resultType="blog" parameterType="blog">
select id, title, author, create_time, views from blog
# where 1=1
<where>
<if test="author!=null">
author=#{author}
if>
<if test="views!=null">
and views>#{views}
if>
where>
select>
mapper>
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.baidou.mapper.BlogMapper">
<sql id="select_all">
select id, title, author, create_time, views
from blog
sql>
<select id="selectBlogListByAuthor" resultType="blog" parameterType="string">
<include refid="select_all">include>
<if test="author != null">
where author=#{name}
if>
select>
<select id="selectBlogListByAuthorAndViews" resultType="blog" parameterType="blog">
<include refid="select_all">include>
# where 1=1
<where>
<if test="author!=null">
author=#{author}
if>
<if test="views!=null">
and views>#{views}
if>
where>
select>
mapper>
set标签可以用于动态包含需要更新的列,忽略其它不更新的列。
需求:通过id动态修改博客信息。
编写接口:
// 修改博客信息
void update(Blog blog);
编写sql映射文件:
<update id="update">
update mybatis.blog
<set>
<if test="author!=null and author!=''">
author = #{author},
if>
<if test="title!=null and title!=''">
title = #{title},
if>
<if test="views!=null">
views = #{views}
if>
set>
where id=#{id}
update>
编写测试:
public class Test {
public static void main(String[] args) {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
BlogMapper mapper = sqlSession .getMapper(BlogMapper.class);
Blog blog = new Blog();
blog.setId("1fae806d59d14b089270b403e78cb7cd");
blog.setAuthor("张三");
blog.setTitle("分手大师");
blog.setViews(666);
mapper.update(blog);
MyBatisUtils.commitAndClose(sqlSession);
}
}
使用注解可以代替映射文件中的配置,但是简单的sql可以用注解玩玩,复杂的sql就只能用配置文件啦(提高开发效率,和可读性)。
Mybatis 针对 CURD 操作都提供了相应的注解:
示例:使用注解方式,根据id查询用户。
@Select("select * from user where id=#{id}")
User findUserById(int id);
MyBatis缓存
MyBatis连接池
MyBatis缓存
MyBatis关联查询
MyBatis延迟加载策略