MyBatis笔记(一)——入门与简单Mapper实现CRUD
文章目录
参考: https://www.bilibili.com/video/BV1NE411Q7Nx
视频原作者CSDN: https://blog.csdn.net/qq_33369905
这篇是自己整理了一下,以便自己复习。
1.MyBatis简介
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。
- Mybatis官方中文文档(最好的MyBatis文档)⚡️ : http://www.mybatis.org/mybatis-3/zh/index.html
- GitHub : https://github.com/mybatis/mybatis-3
2.导入依赖与Maven资源过滤
这个例子是一个只有MyBatis的maven工程,没有整合Spring或SpringBoot:
maven工程依赖:
<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion>
<!-- 父工程 -->
<groupId>org.example</groupId>
<artifactId>MyBatis-study</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>mabatis-01</module>
</modules>
<!-- 导入依赖 -->
<dependencies>
<!-- mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<!-- mysql数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- junit单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
<!-- maven资源过滤 xml-->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
3.MyBatis配置文件MyBatis-config.xml⚡️
- 配置数据库连接信息:driver,url,username,password
- 配置mapper.xml文件的扫描
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 开发环境 <environments default="development"> 还可设置测试环境,生产环境-->
<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://你的ip:3306/数据库名称?useSSL=false&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="账号"/>
<property name="password" value="密码"/>
</dataSource>
</environment>
</environments>
<!-- 每一个mapper都需要在配置文件中注册 mapper.xml 默认从resource-->
<mappers>
<!-- 三种写法 类class 绝对地址url resource(一般用这个) -->
<!-- 举例-->
<!-- <mapper resource="com/piao/dao/UserMapper.xml"/>-->
</mappers>
</configuration>
4.数据表与实体类
建表sql:
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(20) NOT NULL,
`name` varchar(30) DEFAULT NULL,
`pwd` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `user`(`id`,`name`,`pwd`) values (1,'狂神','123456'),(2,'张三','abcdef'),(3,'李四','987654');
User.java(没用Lombok)
public class User {
private int id; //id
private String name; //姓名
private String pwd; //密码
//构造,有参,无参
//set/get
//toString()
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 + '\'' +
'}';
}
}
5.获取SqlSession的工具类
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;
//SqlSessionFactory获取SqlSession
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
//静态代码块,初始时就执行
static {
try {
//从配置文件读取配置,获取SqlSession对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//从SqlSessionFactory获取SqlSession连接
public static SqlSession getSession(){
return sqlSessionFactory.openSession();
}
}
6.(CRUD⚡️)编写DAO接口类与对应的Mapper.xml
6.1 接口类的编写
UserMapper接口类,基本的增删改查接口:
import java.util.List;
//操作数据库的接口
public interface UserMapper {
//查询所有User
List<User> selectUser();
//按照id查询User
User selectUserById(int id);
//插入一个用户 可传对象
void insertUser(User user);
//修改一个用户
void updateUser(User user);
//根据id删除一个用户
void deleteUser(int id);
}
6.2 UserMapper.xml的编写
MyBatis的第一个最主要内容就是xml文件的编写
-
xml有mapper包裹,其namespace属性是规定命名空间,填写该xml对应的DAO接口类,及上述的UserMapper,需要填写全限定名(比如:com.piao.dao.UserMapper)
-
mapper里面写增删改查的标签 select ,insert,update,delete.都通过id属性指定该标签对应mapper接口类中的方法名称。比如第一个select标签中id="selectUser"即该标签对应UserMapper接口类中的selectUser方法
-
resultType 结果类型(将sql执行的结果自动封装成该类型)
-
parameterType 参数类型(基础数据类型或自定义类),在SQL中使用 **#{ }**传参数
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace绑定一个对应的Mapper接口-->
<mapper namespace="com.piao.dao.UserMapper">
<!-- 数据表名称user-->
<!-- id对应 mapper接口的selectUser()方法 resultType:(全限定名)返回结果类型(返回一个) resultMap -->
<select id="selectUser" resultType="com.piao.pojo.User">
select * from user;
</select>
<!-- parameterType参数类型-->
<!-- 传参方式: #{id} id为selectUserById方法中的int类型参数id selectUserById(int id);-->
<select id="selectUserById" parameterType="int" resultType="com.piao.pojo.User">
select * from user where id = #{id};
</select>
<!-- 插入一个用户 参数传来一个对象 可以直接从里面取属性的值-->
<insert id="insertUser" parameterType="com.piao.pojo.User">
insert into user(id,name,pwd) values (#{id},#{name},#{pwd});
</insert>
<!-- 修改用户,同理-->
<update id="updateUser" parameterType="com.piao.pojo.User">
update user set name=#{name} ,pwd=#{pwd} where id=#{id};
</update>
<!-- parameterType="int"可省略 基本数据类型可省略-->
<delete id="deleteUser" parameterType="int">
delete from user where id =#{id};
</delete>
</mapper>
7.junit测试上述mapper接口
junit最基本的操作:
@BeforeClass – 表示在类中的任意public static void方法执行之前执行
@AfterClass – 表示在类中的任意public static void方法执行之后执行
@Before – 表示在任意使用@Test注解标注的public void方法执行之前执行
@After – 表示在任意使用@Test注解标注的public void方法执行之后执行
@Test – 使用该注解标注的public void方法会表示为一个测试方法
增删改都需要提交数据库事务!否则操作不生效·
数据库事务( transaction)是访问并可能操作各种数据项的一个数据库操作序列,
这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。
事务由事务开始与事务结束之间执行的全部数据库操作组成。
具体的测试代码,测试了userMapper接口中的所有方法:
package com.piao.dao;
import com.piao.pojo.User;
import com.piao.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
//测试
public class UserMapperTest {
static SqlSession session;
static UserMapper mapper;
//测试前初始化SqlSession 与mapper
@Before
public void init() {
session = MybatisUtils.getSession();//获取sqlsession
//session.selectList("com.kuang.mapper.UserMapper.selectUser");//获取session中的mapper 方法一
mapper = session.getMapper(UserMapper.class);//获取session中的mapper 方法二(一般用这个)
}
//测试后统一关闭SqlSession
@After
public void closeSqlSession() {
//关闭sqlsession
session.close();
}
//测试查询所有用户selectUser()
@Test
public void testSelectUser() {
System.out.println("测试查询所有用户selectUser()");
List<User> users = mapper.selectUser();
for (User user : users) {
System.out.println(user);
}
System.out.println();
}
//测试按照id查询用户selectUserById()
@Test
public void testSelectUserById() {
System.out.println("测试按照id查询用户selectUserById()");
User user = mapper.selectUserById(2);
System.out.println(user);
System.out.println();
}
//测试插入一个用户insertUser(User user)
@Test
public void testInsertUser() {
System.out.println("测试插入一个用户insertUser(User user)");
User user = new User(4, "王五", "2333");
mapper.insertUser(user);
session.commit();//提交事务 原生jdbc则需要开启事务执行sql后提交事务
System.out.println("插入用户 " + user);
}
//测试修改一个用户updateUser(User user);
@Test
public void testUpdateUser(){
System.out.println("测试修改一个用户updateUser(User user);");
// name 王五-》王五五
User user = new User(4, "王五五", "2333");
mapper.updateUser(user);
System.out.println("修改用户 " + user);
session.commit();//提交事务
}
//测试根据id删除一个用户
@Test
public void testDeleteUser(){
System.out.println("测试根据id删除一个用户");
User user =mapper.selectUserById(4);
System.out.println("删除用户 " + user);
mapper.deleteUser(4);
session.commit();//提交事务
}
}
拓展1.Map传参
若实体类属性 或 数据库字段比较多时,可以考虑使用Map传参。
这是DAO到数据库这里使用map传参,而且是属性比较多的时候可以考虑使用。
不建议在Controller层中使用Map传参!不利于维护
UserMapper接口
//插入一个用户 可传对象
void insertUser(User user);
//笔记2
//插入一个用户 使用Map传参
void insertUserByMap(Map<String,Object> map);
UserMapper.xml
<!-- 插入一个用户 参数传来一个对象 可以直接从里面取属性的值-->
<insert id="insertUser" parameterType="com.piao.pojo.User">
insert into MyBatis.user(id,name,pwd) values (#{id},#{name},#{pwd});
</insert>
<!-- 笔记二-->
<!-- 插入一个用户 参数传来一个Map 此处变为需要与map中的key一一对应-->
<!-- 好处:数据库字段多时,考虑使用map,因为无需实例化一个实体类 -->
<insert id="insertUserByMap" parameterType="map">
insert into MyBatis.user(id,name,pwd) values (#{userId},#{userName},#{userPassword});
</insert>
测试:
//测试
public class UserMapperTest {
static SqlSession session;
static UserMapper mapper;
//初始化SqlSession 与mapper
@Before
public void init() {
session = MybatisUtils.getSession();//获取sqlsession
mapper = session.getMapper(UserMapper.class);//获取session中的mapper 方法二(一般用这个)
}
//测试后统一关闭SqlSession
@After
public void closeSqlSession() {
session.close();
}
//笔记2
@Test
public void testInsertUserByMap(){
Map<String, Object> map = new HashMap<>();
map.put("userId",5);
map.put("userName","赵六");
map.put("userPassword","13100");
mapper.insertUserByMap(map);
session.commit();//提交事务
}
好处,举例说明:例如修改密码的场景,其实只需要传id和password就可以了,如果User这个实体类属性比较多,而且初始化时有的字段不能为空(比如使用了用于参数校验的@NotNull, @NotBlank, @NotEmpty ),这样就必须拿到这些属性值,而使用Map传参数就不需要。
拓展2.模糊查询 注意点(防止SQL注入的问题)
1.Java代码执行时,传递通配符 % %(推荐)
Java中
List<User> userList = mapper.selectUserLike("%李%");
xml中
select * from user where name like #{value};
2.在SQL拼接时使用通配符! 会引起sql注入
Java中
List<User> userList = mapper.selectUserLike("李");
xml中
select * from user where name like "%"#{value}"%";
拓展3.参数传递注解@Param
用map也行
场景:根据 密码 和 名字 查询用户
1、在接口方法的参数前加 @Param属性
2、Sql语句编写的时候,直接取@Param中设置的值即可,不需要单独设置参数类型
@Param用于给方法参数起一个名字,需要注意:
- 在方法只接受一个参数的情况下,可以不使用@Param。
- 在方法接受多个参数的情况下,建议一定要使用@Param注解给参数命名。
- 如果参数是 JavaBean , 则不能使用@Param。
接口定义:
User selectUserByNP(@Param("username") String username,@Param("pwd") String pwd);
xml配置
<select id="selectUserByNP" resultType="com.piao.pojo.User">
select * from user where name = #{username} and pwd = #{pwd}
</select>
测试
//拓展 多参数(用map也行)
@Test
public void testSelectUserByNP(){
User user = mapper.selectUserByNP("张三", "abcdef");
System.out.println(user);
}
拓展4 #与$的区别
#与$的区别
在mybatis中使用#{}可以防止sql注入,提高系统安全性。
- {}是预编译处理
- ${}是字符串替换
-
#{ } 的作用主要是替换预编译语句(PrepareStatement)中的占位符 ? 【推荐使用】
INSERT INTO user (name) VALUES (#{name}); INSERT INTO user (name) VALUES (?);
-
${ } 的作用是直接进行字符串替换
INSERT INTO user (name) VALUES ('${name}'); INSERT INTO user (name) VALUES ('kuangshen');
拓展5 自动提交事务
//SqlSessionFactory获取SqlSession
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
//静态代码块,初始时就执行
static {
try {
//从配置文件读取配置,获取SqlSession对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//从SqlSessionFactory获取SqlSession连接
public static SqlSession getSession(){
//return sqlSessionFactory.openSession();//默认为flase,需要手动commit事务
return sqlSessionFactory.openSession(true);//自动提交事务
}
}
MyBatis笔记合集
MyBatis笔记(一)——入门与简单Mapper实现CRUD
MyBatis笔记(二)——配置(环境配置,别名优化,mapper映射器,属性 properties),生命周期和作用域
MyBatis笔记(三)——ResultMap结果集映射,日志,分页的多种实现方式
MyBatis笔记(四)——动态SQL元素(if,where,set,trim,choose,when,otherwise,foreach),SQL片段