一张图理解mybatis:没有mybatis的时候用jdbc去写操作数据库的代码,非常复杂。mybatis的代码在下面可以看到,比jdbc简单了好几倍。
一、简介
1.1 什么是MyBatis
MyBatis是一个持久层框架,既然和持久层有关那就可以简单理解成和数据库有关,既然是框架那么就肯定是为了简化数据库有关的操作。由于传统的JDBC代码处理数据库有关的代码太复杂,所以出现了MyBatis来快速处理数据库。
1.2 MyBatis的特点
- 支持定制化SQL、存储过程、高级映射
- 省略了手动编写JDBC代码和手动设置参数、获取结果集
- 可以使用简单的XML、注解来配置和映射原生类型、接口和Java的POJO为数据库中的记录
- SQL语句和代码分离,SQL写在xml中便于统一管理和优化
- MyBatis不会对应用程序或数据库的现有设计强加任何影响
二、入门
1.在mysql中执行如下脚本:
CREATE DATABASE db_Mybatis;
USE db_Mybatis;
CREATE TABLE `user`(
`id` VARCHAR(12) PRIMARY KEY,
`username` VARCHAR(20),
`password` VARCHAR(20)
)engine=INNODB DEFAULT CHARSET=utf8;
show tables;
describe `user`;
SELECT * FROM `user`;
INSERT INTO `user`
VALUES('1','qq','123456');
INSERT INTO `user`
VALUES('2','ww','123456')
2.创建一个maven项目
2.1 用到mybatis需要配置什么?
1. pom.xml 文件
- 文件指定用到的jar包
- 添加对抗“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</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
<!-- 版本要和mysql的版本匹配起来,mysql是5开头的话这个也要以5开头,如果是8开头。。。-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.32</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.13</version>
</dependency>
</dependencies>
<!-- 因为maven的约定大于配置,资源文件都约定放在resources目录。
但是在项目中可能不仅仅会将所有的资源配置文件都放在resources中。
那么此时默认的maven项目构建编译时就不会将我们其他目录下的资源配置文件导出到target目录下,
就会导致我们的资源配置文件读取失败,导致项目出现异常错误。
可以在pom文件中添加如下配置来解决该类问题:
-->
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>
2. mybatis核心配置文件
在src/resources文件夹下新建一个mybatis-config.xml文件(命名随便)
环境信息:比如连接数据库所必须的url、用户名、密码等等信息。
注册映射:所有的mapper.xml配置文件都要在这里注册。
<?xml version="1.0" encoding="UTF8" ?>
<!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://localhost:3306/db_mybatis?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--每个Mapper.xml都需要在mybatis核心配置文件中注册 -->
<mappers>
<mapper resource="userMapper.xml"/>
</mappers>
</configuration>
2.2 写代码
- 实体类:既然是和数据库进行交互,那么就要有实体类和数据库中的每个表一一对应,每个属性的类型和名称要和数据库表中的一样,否则可能无法匹配上。
package pojo;
public class User {
private String id;
private String username;
private String password;
public User() {}
public String getId() { return this.id; }
public void setId(String id) { this.id = id; }
public String getUsername() { return this.username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return this.password; }
public void setPassword(String password) { this.password = password; }
public String toString() {
return "User [id=" + this.id + ", username=" + this.username + ", password=" + this.password + "]\n";
}
}
- MyBatis工具类:用来连接数据库、创建与数据库进行交互的SqlSession类的实体对象
MyBatis中有三个比较重要的类:
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 ;
//获取SqlSessionFactory对象
static {
try {
String resource = "mybatis-config.xml"; //MyBatis的核心配置文件,没指定路径也能读到吗?去classpath下递归读!
InputStream inputStream = Resources.getResourceAsStream(resource); //读取配置文件中的信息
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //创建SqlSessionFactory对象
} catch (IOException e) {
e.printStackTrace();
}
}
//创建SqlSeesion对象
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession() ;
}
}
- Mapper接口类:指出想要实现的方法,只需要构造出方法名即可
package dao;
import pojo.User;
import java.util.List;
public interface UserMapper {
List<User> getAllUser();
void insertUsers();
}
- Mapper.xml配置文件:通过配置文件将Mapper接口类和MyBatis联系起来,在该配置文件中写SQL语句即可,从而将SQL和代码分离。之后MyBatis就会根据这个配置文件进行相应的操作。
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="dao.UserMapper">
<select id="getAllUser" resultType="pojo.User">
select * from `user` <!--在select元素中间写需要执行的SQL语句 -->
</select>
</mapper>
其中有几个重要的属性:
- 测试类
import dao.UserMapper;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import pojo.User;
import java.util.List;
public class MyTest {
@Test
public void test01(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
try {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//userMapper.insertUsers();
List<User> allUser = userMapper.getAllUser(); //底层是SQL的执行
for(User u:allUser){
System.out.println(u);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
}
运行结果:
三、mybatis实现增删改查
增删改一定要提交事务!不然无法生效!
1、带条件的查询
mysql带条件的查询放到Java里其实就是带参数的方法。
UserMapper.java
public interface UserMapper {
User getUserById(String id);
}
userMapper.xml
<mapper namespace="dao.UserMapper">
<select id="getUserById" resultType="pojo.User" parameterType="java.lang.String">
select * from `user` where id=#{id} <!--和写SQL语句是有区别的,where后面的字符串不用加单引号-->
</select>
</mapper>
测试类:
SqlSession sqlSession = MybatisUtils.getSqlSession();
try {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User u = userMapper.getUserById("1"); //底层是SQL的执行
System.out.println(u);
} catch (Exception e) {
e.printStackTrace();
} finally{
sqlSession.close();
}
需要注意2点:
- 有入参的时候,要用<select>的parameterType属性指定入参的类型(如果入参是基本数据类型,可以省略不写parameterType属性)
- #{id} 可以直接获取入参的值
当方法存在多个基本数据类型参数,实际项目中都会在接口里用@Param参数规定参数的名字,这是一个规范
public interface UserMapper {
User getUserById(@Param("idid") String id, @Param("name") String stuName);
}
<select id="getUserById" resultType="pojo.User" > <!--不需要parameterType了-->
select * from `user` where id=#{idid} and stuName=#{name} <!--用@Param里的名字-->
</select>
2、插入
UserMapper.java
public interface UserMapper {
void addUser(User user);
}
userMapper.xml
<mapper namespace="dao.UserMapper">
<!-- #{..}可以直接取User的各个属性-->
<insert id="addUser" parameterType="pojo.User">
insert into `user` values(#{id},#{username},#{password})
</insert>
</mapper>
测试类
@Test
public void test01(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
try {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
userMapper.addUser(new User("3","three","123456"));
sqlSession.commit(); //别忘了提交事务!
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
需要注意:
- 当接口参数为实体类时,可以用#{id}直接取id属性
- 增删改查一定要提交事务才能生效
- 如果创建sqlSession的时候,将提交事务设为true,就不用手动提交事务了。
//创建SqlSession对象
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession(true) ; //true
}
3、删除
public interface UserMapper {
void deleteUser(String id);
}
UserMapper.xml
<delete id="deleteUser" parameterType="java.lang.String">
delete from `user` where id=#{id}
</delete>
测试类
public class MyTest {
@Test
public void test01(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
try {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
userMapper.deleteUser("1");
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
}
4、更改
UserMapper.java
public interface UserMapper {
void updateUser(User user);
}
UserMapper.xml
<update id="updateUser" parameterType="pojo.User">
update `user` set username=#{username},password=#{password} where id=#{id}
</update>
测试类
public class MyTest {
@Test
public void test01(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
try {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
userMapper.updateUser(new User("3","4/24","123456"));
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
}
注意:因为Mapper方法只能传递一个参数,所以update方法传递的参数应该是对象。而不能像这样传递好几个值:
void updateUser(String id,String username); //×
void updateUser(User user); //√,只能传递一个user对象
但是如果这个表有40个字段,我们只想改其中一个字段的值,按照上面的做法,就要在调用updateUser方法的时候传递40个字段的值(其中39个传空值) 。肯定有其他解决方法的!
== 多个参数如何传参?==
- 用map
- 或者@Param注解
法(一):jd实战中用的也是map!
用map<key,value>的key指定字段名,value用来传值,这样如果我们要修改一个有40个字段的表的其中一个字段,只需要用map指定这个字段还有用来查询的字段就好啦!
public interface UserMapper {
void updateUserById(Map<String,Object> map);
}
<update id="updateUserById" parameterType="map"> <!--Map的入参类型就写map-->
update `user` set username=#{hei} where id=#{giveYouThisId} <!--给字段随便起名-->
</update>
测试类
public class MyTest {
@Test
public void test01(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
try {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("hei","heihei"); //给字段随便起名"hei"
map.put("giveYouThisId","3"); //给字段随便起名"giveYouThisId"
userMapper.updateUserById(map);
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
}
法(二):用@Param注解
5、模糊查询
public interface UserMapper {
List<User> getUserByName(String username);
}
<select id="getUserByName" parameterType="java.lang.String">
select * from `user` where username like #{username}
</select>
测试类
public class MyTest {
@Test
public void test01(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
try {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.getUserByName("%李%");
for (User u : users){
System.out.println(u);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
sqlSession.close();
}
}
}