因为小学期项目的需要,通过b站学习数据库接口Mybatis并整理学习笔记。
因为记录了所有一开始接触Mybatis的内容,所以文章较长,如果有需要查看对应部分的内容,建议使用文章目录。
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
持久化就是将程序的数据在持久状态和瞬时状态转化的过程
Dao层、Service层、Controller层等
完成持久化工作的代码块 层界限十分明显
帮助程序员将数据存入到数据库中。
方便,简化、框架、自动化,更容易上手。
传统的JDBC代码太复杂了。
优点:
通过终端新建一个数据库,并导入几条数据供之后使用
CREATE DATABASE mybatis;
use mybatis;
CREATE TABLE user(
id INT(20) not null PRIMARY KEY,
name VARCHAR(30) DEFAULT NULL,
pwd VARCHAR(30) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO user (id,name,pwd) VALUES
(1,'Tommy','123456'),
(2,'Danny','123456'),
(3,'Henry','123890');
通过quickstart新建一个maven项目后,在设置中选用本地的maven,并删除系统自动生成的src,以方便后续代码的编写。
在项目自带的pom.xml文件中导入编写Mybatis所需要的maven依赖。此时因为删除了项目生成是所具有的src文件夹,此时可以认为刚刚创建的maven项目为一个父工程。
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>org.examplegroupId>
<artifactId>MybatisartifactId>
<packaging>pompackaging>
<version>1.0-SNAPSHOTversion>
<modules>
<module>mybatis-01module>
<module>mybatis-02module>
modules>
<dependencies>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.18version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.2version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
dependencies>
<properties>
<maven.compiler.source>18maven.compiler.source>
<maven.compiler.target>18maven.compiler.target>
properties>
<build>
<resources>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
resource>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>truefiltering>
resource>
resources>
build>
project>
需要注意的是:导入依赖的时候可能需要一定的时间,请耐心的等待(博主一开始以为是maven安装的问题,导致浪费了许多时间)
新建一个子模块,并在子模块中的resources文件夹中创建mybatis-config.xml文件。(文件命名约定俗成)
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="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/hao/dao/UserMapper.xml"/>
mappers>
configuration>
首先需要补充的代码是四行**< property/>**标签内的代码,第一行为连接mysql的通用代码,剩下三行需根据本人数据库的具体情况编写。
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。
package com.hao.utils;
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;
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 命令所需的所有方法。
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession();
}
}
创建一个与数据库中的实体具有相同属性的类。
package com.hao.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;
}
@Override
public String toString() {
return "user{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
接口中需要实现的方法,即对数据库进行操作的逻辑。
程序需要通过数据库接口对数据库的数据进行几种不同的操作,即需要编写几种不同的方法,并在4.3中通过配置实现。
package com.hao.dao;
import com.hao.pojo.User;
import java.util.List;
public interface UserMapper {
List<User> getUserList();
}
利用SqlSession实现基于xml文件的sql语句的映射。
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.newer.dao.UserMapper">
<select id="getUserList" resultType="com.hao.pojo.User">
SELECT * FROM mybatis.user
select>
mapper>
namespace:即命名空间,包名要和mapper接口的包名保持一致
使用junit进行测试。
package com.hao.dao;
import com.hao.pojo.User;
import com.hao.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class UserMapperTest {
@Test
public void test() {
//第一步:获得SqlSession对象
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserList();
for (User user : userList) {
System.out.println(user);
}
//关闭sqlSession
sqlSession.close();
}
}
这里需要注意的是:
即几种常用的sql语句的映射。
选择,查询语句
package com.hao.dao;
import com.hao.pojo.User;
import java.util.List;
public interface UserMapper {
//根据id查询用户
User getUserById(int id);
}
参数
<select id="getUserById" resultType="com.hao.pojo.User" parameterType="int">
/*定义sql*/
SELECT * FROM mybatis.user WHERE id = #{id};
select>
**#{}**接受定义的方法中的的传入的参数。
@Test
public void getUserById(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.getUserById(1);
System.out.println(user);
sqlSession.close();
}
需要提交事务
package com.hao.dao;
import com.hao.pojo.User;
import java.util.List;
public interface UserMapper {
// 插入一个用户
int addUser(User user);
}
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hao.dao.UserMapper">
<insert id="addUser" parameterType="com.hao.pojo.User">
INSERT INTO mybatis.user(id, name, pwd) VALUES (#{id}, #{name}, #{pwd});
insert>
mapper>
@Test
public void testAddUser() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int result = mapper.addUser(new User(5,"Horace","123444"));
if (result > 0) {
System.out.println("Success");
}
// 提交事务
sqlSession.commit();
sqlSession.close();
}
需要提交事务
package com.hao.dao;
import com.hao.pojo.User;
import java.util.List;
public interface UserMapper {
// 修改用户
int updateUser(User user);
}
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hao.dao.UserMapper">
<update id="updateUser" parameterType="com.hao.pojo.User">
UPDATE mybatis.user SET name = #{name}, pwd = #{pwd} WHERE id = #{id};
update>
mapper>
@Test
public void testUpdateUser() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int result = mapper.updateUser(new User(4,"Eric","123123"));
if (result > 0) {
System.out.println("Success");
}
sqlSession.commit();
sqlSession.close();
}
需要提交事务
package com.hao.dao;
import com.hao.pojo.User;
import java.util.List;
public interface UserMapper {
// 删除用户
int deleteUser(int id);
}
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hao.dao.UserMapper">
<delete id="deleteUser" parameterType="int">
DELETE FROM mybatis.user WHERE id = #{id};
delete>
mapper>
@Test
public void testDeleteUser() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int result = mapper.deleteUser(5);
if (result > 0) {
System.out.println("Success");
}
sqlSession.commit();
sqlSession.close();
}
非常重要
我们的实体类,或者数据库中的表,字段或者参数过多,我们应当考虑使用Map。
万能Map,无需了解对象中有哪些元素,传递map的key即可。
即在遇到实体类的属性与表的属性不匹配的时候,可以利用map来进行传值!!!
使用map可以随意制造参数,但是使用对象的话,若参数不为空,则需要列出所有不为空的参数。
package com.hao.dao;
import com.hao.pojo.User;
import java.util.List;
public interface UserMapper {
int addUser2(Map<String, Object> map);
}
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hao.dao.UserMapper">
<insert id="addUser2" parameterType="com.hao.pojo.User">
INSERT INTO mybatis.user(id, name, pwd) VALUES (#{userid}, #{userName}, #{passWord});
insert>
mapper>
@Test
public void testAddUser2() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String, Object> map = new HashMap<>();
map.put("userid", 5);
map.put("userName", "Horace");
map.put("passWord", "222333");
mapper.addUser2(map);
// 提交事务
sqlSession.commit();
sqlSession.close();
}
Map传递参数,直接在sql中取出key即可: parameterType=“map”
对象传递参数,直接在sql中取对象的属性即可: parameterType=“Object”
只有一个基本类型参数的情况下,可以直接在sql中取得。
两种使用方法:
package com.hao.dao;
import com.hao.pojo.User;
import java.util.List;
public interface UserMapper {
// 模糊查询用户
List<User> getUserLike(String name);
}
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hao.dao.UserMapper">
<select id="getUserLike" resultType="com.hao.pojo.User">
SELECT * FROM mybatis.user WHERE name LIKE #{value};
select>
<select id="getUserLike" resultType="com.hao.pojo.User">
SELECT * FROM mybatis.user WHERE name LIKE "%"#{value}"%";
select>
mapper>
//传递通配符
@Test
public void testLike() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserLike("%Da%");
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
//在sql语句中实现
@Test
public void testLike() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUserLike("Da");
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
mybatis-config.xml
MyBatis的配置文件包含了会深深影响MyBatis行为的设置和属性信息
MyBatis 可以配置成适应多种环境。
不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
在标签中用default关键词进行环境的选择
可以通过 properties属性 来实现引用配置文件。
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。
在resource中编写 db.properties 文件
driver = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8
username = root
password = 1234556
原本转译的**&**,需要改回 &!!!
在核心配置文件中引入.properties文件,需要注意的是
The content of element type “configuration” must match “(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)”. (如果插入的properties标签位置不对的时候,会有上述错误)。
<properties resource="db.properties"/>
<properties resource="db.properties">
<property name="username" value="root"/>
<property name="password" value="abc123"/>
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>
需要注意的是:
类型别名可为 Java 类型设置一个缩写名字。
它仅用于 XML 配置,意在降低冗余的全限定类名书写。
<typeAliases>
<typeAlias type="com.hao.pojo.User" alias="User"/>
typeAliases>
<typeAliases>
<package name="com.hao.pojo"/>
typeAliases>
@Alias(“writer”)
public class Writer {
…
}
对应的mapper.xml文件可以使用别名以简化
<select id="getUserList" resultType="User">
SELECT * FROM mybatis.user
select>
需要注意的是:
我们需要告诉 MyBatis 到哪里去找到这些语句。
<mappers>
<mapper resource="com/hao/dao/UserMapper.xml"/>
mappers>
<mappers>
<mapper class="com.hao.dao.UserMapper"/>
mappers>
除了第一种没有限制条件,其他两种有限制条件
生命周期,和作用域是至关重要的,因为错误的使用会导致非常严重的并发问题。
SqlSessionFactoryBuilder:
SqlSessionFactory:
SqlSession:
拷贝之前创建的项目,并修改User类的实例变量pwd为password。
运行测试后会发现password对应的数据为null。
<select id="getUserById" parameterType="int" resultType="User">
SELECT id,name,pwd as password FROM mybatis.user WHERE id=#{id}
select>
结果集映射
(id, name, pwd) -> (id, name, password)
<resultMap id="UserMap" type="User">
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="pwd" property="password"/>
resultMap>
<select id="getUserById" parameterType="int" resultMap="UserMap">
SELECT * FROM mybatis.user WHERE id=#{id}
select>
resultMap:
result:
ResultMap 的设计思想是,对于简单的语句根本不需要配置显式的结果映射,而对于复杂一点的语句只需要描述它们的关系就行了。
如果一个数据库操作,出现了异常,我们需要排错。
日志就是最好的助手!
在Mybatis核心配置文件中配置日志
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
settings>
Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件:
<dependencies>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
dependencies>
#将等级为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/hao.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
<settings>
<setting name="logImpl" value="LOG4J"/>
settings>
//在要使用Log4j 的类中,导入org.apache.log4j.Logger;
import org.apache.log4j.Logger;
public class UserMapperTest {
//日志对象,加载参数为当前类的class
static Logger logger = Logger.getLogger(UserMapperTest.class);
@Test
public void testLog4j() {
//日志级别
logger.info("info:进入了testLog4j方法");
logger.debug("debug:进入了testLog4j");
logger.error("error:进入了testLog4j");
}
}
SELECT * FROM user LIMIT startIndex,pageSize;
SELECT * FROM user LIMIT 3;
// 分页(万能map)
List<User> getUserByLimit(Map<String, Integer> map);
<select id="getUserByLimit" parameterType="map" resultType="user">
SELECT * FROM mybatis.user LIMIT #{startIndex}, #{pageSize};
select>
@Test
public void testGetUserLimit() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String, Integer> map = new HashMap<>();
map.put("startIndex", 0);
map.put("pageSize", 2);
List<User> userList = mapper.getUserByLimit(map);
for (User user: userList) {
System.out.println(user);
}
sqlSession.close();
}
不再使用SQL实现分页
// 分页2
List<User> getUserByRowBounds();```
```xml
<!--分页2-->
<select id="getUserByRowBounds" resultMap="UserMap">
SELECT * FROM mybatis.user;
</select>
@Test
public void getUserByRowBounds(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//RowBounds实现
RowBounds rowBounds = new RowBounds(1, 2);
//通过java代码层面实现分页
List<User> userList = sqlSession.selectList("com.hao.dao.UserMapper.getUserByRowBounds",null,rowBounds);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
大家之前都学过面向对象编程,也学习过接口,但在真正的开发中,很多时候我们会选择面向接口编程
@Select("SELECT * FROM user")
List<User> getUsers();
<mappers>
<mapper class="com.hao.dao.UserMapper"/>
mappers>
@Test
public void test() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.getUsers();
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
需要注意的是:
使用注解来映射简单语句会使代码显得更加简洁,然而对于稍微复杂一点的语句,Java 注解就力不从心了,并且会显得更加混乱。因此,如果你需要完成很复杂的事情,那么最好使用 XML来映射语句
本质:反射机制实现
底层:动态代理!
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession(true);
}
自动提交
@Select(("SELECT * FROM user WHERE id = #{id}"))
User getUserById(@Param("id") int id);
方法存在多个参数,所有参数前面必须加上@Param注解.
#{id}必须与Param中的参数一致。
@Test
public void test() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.getUserById(1);
System.out.println(user);
sqlSession.close();
}
@Insert("INSERT INTO user(id,name,pwd) values(#{id},#{name},#{password})")
int addUser(User user);
@Test
public void test() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.addUser(new User(6, "Horace","123123"));
sqlSession.close();
}
@Update("UPDATE user SET name = #{name}, pwd=#{password} WHERE id = #{id}")
int updateUser(User user);
@Test
public void test() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.updateUser(new User(5, "Roy","213321"));
sqlSession.close();
}
@Delete("DELETE FROM user where id = #{uid}")
int deleteUser(@Param("uid") int id);
@Test
public void test() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.deleteUser(6);
sqlSession.close();
}
我们必须要将接口注册绑定到我们的核心配置文件中!
可以使用通配符
<mappers>
<mapper resource="com/hao/dao/*Mapper.xml"/>
mappers>
关于@Param()注解
<dependencies>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.10version>
dependency>
dependencies>
自动生成:无参构造,get、set、toSring、hashcode、equals
@Data
public class User {
private int id;
private String name;
private String password;
}
提供有参和无参构造函数
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,‘Yasir’);
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,‘Horace’,1);
INSERT INTO student(id,name,tid) VALUES (2,‘Danny’,1);
INSERT INTO student(id,name,tid) VALUES (3,‘Tommy’,1);
INSERT INTO student(id,name,tid) VALUES (4,‘Henry’,1);
INSERT INTO student(id,name,tid) VALUES (5,‘Eric’,1);
即子查询
// Student
public List<Student> getStudent();
// Teacher
@Select("SELECT * FROM teacher WHERE id = #{tid}")
Teacher getTeacher(@Param("tid") int id);
<select id="getStudent" resultMap="StudentTeacher">
SELECT * FROM student;
select>
<resultMap id="StudentTeacher" type="Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
resultMap>
<select id="getTeacher" resultType="Teacher">
SELECT * FROM teacher WHERE id = #{id};
select>
因为直接查询无法显示复杂的对象,所以使用resultMap进行结果集映射:id->type
使用association标签处理复杂的属性(利用MySQL语句进行理解)
@Test
public void testStudent() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = mapper.getStudent();
for (Student student : students) {
System.out.println(student);
}
sqlSession.close();
}
即联表查询
// Student
public List<Student> getStudent();
// Teacher
@Select("SELECT * FROM teacher WHERE id = #{tid}")
Teacher getTeacher(@Param("tid") int id);
<select id="getStudent2" resultMap="StudentTeacher2">
SELECT s.id sid, s.name sname, t.name tname
FROM student s, teacher t WHERE s.tid = t.id;
select>
<resultMap id="StudentTeacher2" type="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
association>
resultMap>
通过select标签得到结果,同理直接查询无法显示复杂的对象,所以使用resultMap进行结果集映射:id->type
使用association标签处理复杂的属性,直接利用property和javaType确定(结合上面两个result标签,可以发现这三个标签就象征着查询得到的Student对象的3个属性)
@Test
public void testStudent2() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = mapper.getStudent2();
for (Student student : students) {
System.out.println(student);
}
sqlSession.close();
}
// 获取指定老师下的所有学生及老师的信息
Teacher getTeacher(@Param("tid") int id);
<select id="getTeacher" resultMap="TeacherStudent">
SELECT s.id sid, s.name sname, t.name tname, t.id tid
FROM student s, teacher t
WHERE s.tid = t.id and t.id = #{tid};
select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
collection>
resultMap>
@Test
public void test() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacher = mapper.getTeacher(1);
System.out.println(teacher);
sqlSession.close();
}
// 获取指定老师下的所有学生及老师的信息
Teacher getTeacher2(@Param("tid") int id);
<select id="getTeacher2" resultMap="TeacherStudent2">
SELECT * FROM mybatis.teacher WHERE id = #{tid}
select>
<resultMap id="TeacherStudent2" type="Teacher">
<collection property="students" column="id" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId"/>
resultMap>
<select id="getStudentByTeacherId" resultType="Student">
SELECT * FROM mybatis.student WHERE tid = #{tid}
select>
@Test
public void test2() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacher = mapper.getTeacher2(1);
System.out.println(teacher);
sqlSession.close();
}
动态SQL就是指根据不同的条件生成不同的SQL语句。
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。
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;
<dependencies>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.10version>
dependency>
dependencies>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
<setting name="mapUnderscoreToCamelCase" value="true"/>
settings>
@Data
public class Blog {
private int id;
private String title;
private String author;
private Date createTime;
private int views;
}
package com.hao.dao;
import com.hao.pojo.Blog;
public interface BlogMapper {
// 插入数据
int addBlog(Blog blog);
}
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hao.dao.BlogMapper">
<insert id="addBlog" parameterType="blog">
INSERT INTO mybatis.blog(id, title, author, create_time, views)
VALUES (#{id},#{title},#{author},#{createTime},#{views});
insert>
mapper>
package com.hao.utils;
import org.junit.Test;
import java.util.UUID;
public class IDUtils {
public static String getId() {
return UUID.randomUUID().toString().replace("-", "");
}
}
@Test
public void addInitBlog() {
SqlSession session = MybatisUtils.getSqlSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = new Blog();
blog.setId(IDUtils.getId());
blog.setTitle("Mybatis");
blog.setAuthor("狂神说");
blog.setCreateTime(new Date());
blog.setViews(9999);
mapper.addBlog(blog);
blog.setId(IDUtils.getId());
blog.setTitle("Java");
mapper.addBlog(blog);
blog.setId(IDUtils.getId());
blog.setTitle("Spring");
mapper.addBlog(blog);
blog.setId(IDUtils.getId());
blog.setTitle("微服务");
mapper.addBlog(blog);
session.close();
}
// 查询博客
List<Blog> queryBlogIF(Map map);
<insert id="addBlog" parameterType="blog">
INSERT INTO mybatis.blog(id, title, author, create_time, views)
VALUES (#{id},#{title},#{author},#{createTime},#{views});
insert>
<select id="queryBlogIF" parameterType="map" resultType="blog">
SELECT * FROM mybatis.blog WHERE true
<if test="title != null">
and title = #{title}
if>
<if test="author != null">
and author = #{author}
if>
select>
可以动态的补充SQL语句
使用where标签进行优化:避免出现where直接连接and而导致的错误(可智能地去掉and)
<select id="queryBlogIF" parameterType="map" resultType="blog">
SELECT * FROM mybatis.blog
<where>
<if test="title != null">
and title = #{title}
if>
<if test="author != null">
and author = #{author}
if>
where>
select>
@Test
public void testQueryBlogIF() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap<>();
// map.put("title","Java");
map.put("author", "狂神说");
List<Blog> blogs = mapper.queryBlogIF(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
类似于java中的switch语句
提供了什么条件,就按提供的条件进行查找
<select id="queryBlogChoose" parameterType="map" resultType="blog">
SELECT * FROM mybatis.blog
<where>
<choose>
<when test="title != null">
title = #{title}
when>
<when test="author != null">
AND author = #{author}
when>
<otherwise>
AND views = #{views}
otherwise>
choose>
where>
select>
@Test
public void testQueryBlogChoose() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap<>();
// map.put("title","Java");
// map.put("author", "狂神说");
map.put("views", 9999);
List<Blog> blogs = mapper.queryBlogChoose(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
<update id="updateBlog" parameterType="map">
UPDATE mybatis.blog
<set>
<if test="title != null">
title = #{title},
if>
<if test="author != null">
author = #{author}
if>
set>
WHERE id = #{id}
update>
set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)
@Test
public void testQueryBlogSet() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap<>();
map.put("title","Python");
map.put("author", "Horace");
map.put("id", "7162ee11d95649f191e6af4b14afd402");
mapper.updateBlog(map);
sqlSession.close();
}
使用trim标签,定制功能
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
trim>
移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。
<trim prefix="SET" prefixOverrides=",">
...
trim>
将一些功能的部分提取出来,方便代码复用
<sql id="if_title_author">
<if test="title != null">
and title = #{title}
if>
<if test="author != null">
and author = #{author}
if>
sql>
<select id="queryBlogIF" parameterType="map" resultType="blog">
SELECT * FROM mybatis.blog
<where>
<include refid="if_title_author">include>
where>
select>
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。
foreach 元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。
它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。
// 查询第1,2,3号记录的博客
List<Blog> queryBlogForeach(Map map);
<select id="queryBlogForeach" parameterType="map" resultType="Blog">
select * from mybatis.blog
<where>
<foreach collection="ids" item="id" open="and (" separator="or" close=")" >
id=#{id}
foreach>
where>
select>
@Test
public void testQueryBlogForeach() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
ArrayList<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(2);
map.put("ids", ids);
List<Blog> blogs = mapper.queryBlogForeach(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
感谢b站狂神说,让我较为快速的了解了如何去编写一个简单的Mybatis项目。这是第一次接触数据库接口,从maven到Mybatis对我来说都是一个比较新鲜的东西。
写这篇笔记主要是为了记录一些重要的笔记,也希望在整理的过程中发现一些自己疏忽的地方。