目录
mybatis简介
首先介绍一下什么是mybatis,不谈它的历史,只大概介绍一下,mybatis是一个持久层框架,支持在XML中编写SQL语句,将java方法与SQL语句进行关联
为什么要用mybatis
在之前,我们可以用原生的JDBC去写,去操作数据库,流程大概是这样的
1、定义连接对象
2、预置对象语句
3、获取连接
4、准备SQL
5、执行SQL
这么写的话,我们的代码重复的地方会非常多,因为每次使用都需要这么写,而增删改的不同,无非在于SQL不同,SQL条件的参数不同,而增删改,映射到java,无非就是对象与数据库的增删改
创建一个原生的mybatis项目
导入依赖
<?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>study_mybatis</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
添加mybatis的配置文件
<?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"><!--引入dtd约束-->
<configuration><!--根标签-->
<!--主要指定数据库连接-->
<!-- 这个environment 的名字可以自定义>
<environments default="mybatisstudy">
<environment id="mybatisstudy">
<transactionManager type="JDBC"/><!--配置事务管理器:固定值JDBC即可,mybatis采用JDBC的方式控制事务-->
<dataSource type="POOLED"><!--配置数据源:固定值POOLED即可。pooled是带有连接池的数据源,是mybatis内置的-->
<!--以下四个参数就是连接数据库的基本参数:注意,property的name取值不能随便写-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/user"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
</configuration>
新建表
CREATE TABLE `usermessage` (
`username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`id` int DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
新建和表对应的实体类
package own.study.vo;
public class User {
private String username;
private String password;
private int id;
public String getUsername() {
return username;
}
public void setUsrname(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
编写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"><!--引入映射文件的约束-->
<!--mybatis中的映射文件必须指定namespace(名称空间),类似java的包一样,可以自定义 -->
<mapper namespace="own.study">
<!--insert:插入数据
id:取值在当前xml文档中要保证唯一(就像在同一个包中,类名要唯一是一样的)
parameterType:指定参数的类型。(要写java实体类的全名称)。此属性可以省略不写
SQL语句:mybatis中的sql语句中的占位符是使用#{number}表示的。注意,不要用${},存在SQL注入问题,表示获取parameterType指定的对象的属性的取值(即mybatis会调用User的getId()获取值,设置为参数)
-->
<insert id="saveUser" parameterType="own.study.vo.User">
insert into usermessage (username,password,id) values(#{username},#{password},#{id});
</insert>
</mapper>
在mybatis的配置文件中添加SQL映射文件
<?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"><!--引入dtd约束-->
<configuration><!--根标签-->
<!--主要指定数据库连接-->
<environments default="mybatisstudy">
<environment id="mybatisstudy">
<transactionManager type="JDBC"/><!--配置事务管理器:固定值JDBC即可,mybatis采用JDBC的方式控制事务-->
<dataSource type="POOLED"><!--配置数据源:固定值POOLED即可。pooled是带有连接池的数据源,是mybatis内置的-->
<!--以下四个参数就是连接数据库的基本参数:注意,property的name取值不能随便写-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/user"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 这儿是用来映射,哪些文件是有SQL的,代码是通过这些SQL文件的namespace加上SQl文件的自定义id去获取的-->
<mapper resource="sql.xml"></mapper>
</mappers>
</configuration>
进行单元测试
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 own.study.vo.User;
import java.io.IOException;
import java.io.InputStream;
public class Test {
@org.junit.Test
public void testInsert () throws IOException {
User user = new User();
user.setId(1);
user.setUsrname("root");
user.setPassword("123456");
// 1、读取mybatis的主配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");//读取mybatis的主配置文件,构建输入流
// 2、获取SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 3、获取SqlSessioinFactory对象
SqlSessionFactory sessionFactory = builder.build(in);
// 4、获取SqlSession对象
SqlSession sqlSession = sessionFactory.openSession();
// 5、调用SqlSession的API保存数据
int num = sqlSession.insert("own.study.saveUser",user);//第一个参数:指定sql语句的位置,就是SQL映射文件中的namespace+id来确定;第二个参数是实体对象
System.out.println("影响到的行数:"+num);
// 6、提交事务:默认情况下,mybaits的事务不是自动提交的
sqlSession.commit();
// 7、释放SqlSession占用的资源
sqlSession.close();
}
}
mybatis用到的类
Resources:是MyBatis提供的工具类,能够从classpath或其他路径加载mybatis的配置文件
SqlSessionFactoryBuilder:根据xml配置文件中的内容构建SqlSessionFactory对象。一旦创建了 SqlSessionFactory,就不再需要它了,就没用了。
SqlSessionFactory:mybatis中最为重要的一个对象,包含了所有配置内容, 一般一个项目就一个,一旦创建了,就应该在项目正常运行期间,保持存在,不应该毁灭或者创建另外一个,factory是一个重量级的对象,创建非常耗费时间与资源,此factory的最佳使用就是让它的作用域是全局,此factory是线程安全的,可以被n个线程共享
SqlSession:每个线程都有自己的sqlsession,sqlsession线程不安全,所以,建议用的时候去获取,不用就shutdown掉
mybatis增加Dao的写法改良
在上面的写法里,虽然可行,但是我们需要写很多麻烦的东西,能不能搞个类,让它自己去映射呢?
进行修改,创建dao类
package own.study.dao;
import own.study.vo.User;
public interface UserDao {
public void saveUser(User user);
}
修改SQL映射文件
修改SQL的映射文件,保持namespace和Dao接口相同
<?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"><!--引入映射文件的约束-->
<!--mybatis中的映射文件必须指定namespace(名称空间),类似java的包一样-->
<mapper namespace="own.study.dao.UserDao">
<!--insert:插入数据
id:取值在当前xml文档中要保证唯一(在同一个包中,类名要唯一是一样的)
parameterType:指定参数的类型。(目前要写java实体类的全名称)。此属性可以省略不写
SQL语句:mybatis中的sql语句中的占位符是使用#{number}表示的。表示获取parameterType指定的
对象的number属性的取值(即mybatis会调用Account的getNumber()获取账户,设置为参数)
-->
<insert id="saveUser" parameterType="own.study.vo.User">
insert into usermessage (username,password,id) values(#{username},#{password},#{id});
</insert>
</mapper>
修改测试类
@org.junit.Test
public void testDaoInsert () throws IOException {
User user = new User();
user.setId(2);
user.setUsrname("root1");
user.setPassword("123456");
// 1、读取mybatis的主配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");//读取mybatis的主配置文件,构建输入流
// 2、获取SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 3、获取SqlSessioinFactory对象
SqlSessionFactory sessionFactory = builder.build(in);
// 4、获取SqlSession对象
SqlSession sqlSession = sessionFactory.openSession();
// 5、动态代理,产生实现类
UserDao userDao = sqlSession.getMapper(UserDao.class);
userDao.saveUser(user);
// 6、提交事务:默认情况下,mybaits的事务不是自动提交的
sqlSession.commit();
// 7、释放SqlSession占用的资源
sqlSession.close();
}
注意事项
SQ映射文件的namespace一定要和Dao接口的路径一毛一样,下面的自定义ID,也一定要和Dao的方法名一毛一样
顺便说一嘴,如果要模糊查询,请不要用
like %${参数名}%
上面这种方式是字符串拼接,存在SQL注入问题,可以用mysql的函数 concat 解决
like concat('%', #{参数}, '%')
动态SQL
如同字面意思,这个SQL是动态的,也就是说,满足什么条件,用什么
mybatis支持动态SQL,提供了判断的标签 if ,格式化的标签 where 、set ,循环的标签 foreach
if标签
编写SQL映射XML文件
<select id="selectByid" parameterType="own.study.vo.User" resultType="own.study.vo.User">
select * from usermessage where 1 = 1
<if test="id %2 == 0">
and id=#{id}
</if>
</select>
编写Dao
public User selectByid(User user);
编写test
@org.junit.Test
public void testSelectByid () throws IOException {
User user = new User();
user.setId(2);
// 1、读取mybatis的主配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");//读取mybatis的主配置文件,构建输入流
// 2、获取SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 3、获取SqlSessioinFactory对象
SqlSessionFactory sessionFactory = builder.build(in);
// 4、获取SqlSession对象
SqlSession sqlSession = sessionFactory.openSession();
// 5、动态代理,产生实现类
UserDao userDao = sqlSession.getMapper(UserDao.class);
// userDao.saveUser(user);
User u = userDao.selectByid(user);
System.out.println(u);
// 6、提交事务:默认情况下,mybaits的事务不是自动提交的
sqlSession.commit();
// 7、释放SqlSession占用的资源
sqlSession.close();
}
查看结果
where标签
where标签用在最外层,作用是:如果where标签的内部,至少有一个if执行了,那就自动加上where关键字,删除第一个if的and关键字,如果where标签内部的所有if都没有被执行,那where标签就啥也不管,啥也不干
改写SQL映射文件
<select id="selectByid" parameterType="own.study.vo.User" resultType="own.study.vo.User">
select * from usermessage
<where>
<if test="id %2 == 0">
and id=#{id}
</if>
</where>
</select>
查看运行结果
set标签
set标签的作用同where标签类似,如果执行了if,那就加上set关键字,并去掉最后一个逗号,如果没有if执行,那就啥也不干,你后边爱干啥干啥
编写SQL映射文件
<update id="updateUser" parameterType="own.study.vo.User">
update usermessage
<set>
<if test="id != null">
username = #{username},
</if>
</set>
<where>
<if test="id != null">
id=#{id}
</if>
</where>
</update>
编写Dao接口
public void updateUser(User user);
编写测试类
@org.junit.Test
public void testUpdateUser() throws IOException {
User user = new User();
user.setId(2);
user.setUsrname("admin");
// 1、读取mybatis的主配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");//读取mybatis的主配置文件,构建输入流
// 2、获取SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 3、获取SqlSessioinFactory对象
SqlSessionFactory sessionFactory = builder.build(in);
// 4、获取SqlSession对象
SqlSession sqlSession = sessionFactory.openSession();
// 5、动态代理,产生实现类
UserDao userDao = sqlSession.getMapper(UserDao.class);
userDao.updateUser(user);
// 6、提交事务:默认情况下,mybaits的事务不是自动提交的
sqlSession.commit();
// 7、释放SqlSession占用的资源
sqlSession.close();
}
运行测试
foreach标签
循环处理,一般用在in条件的使用
编写SQL映射文件
<select id="selectByList" resultType="own.study.vo.User">
select * from usermessage where id in
<foreach collection="idList" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
编写Dao
public List<User> selectByList(@Param("idList") List list);
编写测试
@org.junit.Test
public void testSelectByList() throws IOException {
// 1、读取mybatis的主配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");//读取mybatis的主配置文件,构建输入流
// 2、获取SqlSessionFactoryBuilder对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 3、获取SqlSessioinFactory对象
SqlSessionFactory sessionFactory = builder.build(in);
// 4、获取SqlSession对象
SqlSession sqlSession = sessionFactory.openSession();
// 5、动态代理,产生实现类
UserDao userDao = sqlSession.getMapper(UserDao.class);
List idList = new ArrayList();
idList.add(1);
idList.add(2);
for (User user : userDao.selectByList(idList)) {
System.out.println(user);
}
// 6、提交事务:默认情况下,mybaits的事务不是自动提交的
sqlSession.commit();
// 7、释放SqlSession占用的资源
sqlSession.close();
}
查看结果
mybatis的延迟加载策略
mybatis有一个用法,叫延迟加载策略,延迟加载策略的意思也很简单,那就是等你用到了,我mybatis再去做相关操作
开启mybatis延迟加载策略的方式也很简单,更改mybatis的配置文件
<settings>
<!--打开全局延迟加载开关。默认是false。注意:参数名不能随便写-->
<setting name="lazyLoadingEnabled" value="true"/>
</settings>
mybatis的数据源
mybatis内置了三种数据源
POOLED:带有连接池的数据源。运行效率比较高
UNPOOLED:不带连接池的数据源
JNDI:javaEE的一种技术
mybatis的缓存
缓存介绍
对于变化不频繁的数据,如果我们每次使用都去查询数据库,那么会造成网络带宽的消耗以及数据库资源的占用,我们可以放在缓存里,内存里
一级缓存
一级缓存是sqlsession级别的缓存,只要这个sqlsession不关闭,这个缓存就有效
如果在这个sqlsession有效期间,执行了增、删、改的操作,为了保证数据的有效性,缓存也不会再存在
二级缓存
二级缓存是序列化的缓存,比如我们查询出来数据,将数据放到了一个对象里,二级缓存就是这个对象序列化后的结果,所以,要使用二级缓存,除了开启之外,还需要对象实体类去进行序列化,也就是实现Serializable接口
缓存查询策略
优先查询二级缓存,没有二级缓存,查询一级缓存,没有一级缓存,就查询数据库
开启二级缓存
修改mybatis的配置文件
添加
<setting name="cacheEnabled" value="true"/>
基于注解的mybatis
使用注解的原因
为什么要使用注解,这个原因其实很简单,注解的写法简单,开发效率高
注解的使用
在之前,我们要把SQL语句写到XML文件里,还要进行类型映射,很麻烦,但是使用注解不用,我们可以用@Insert @Update @Delete @Select 这四个注解,直接在Dao上进行SQL的编写及参数的传递
比如:
@Insert("insert into user values(null,#{username})")
void saveUser(User user);
@Update("update user set username=#{username} where id=#{id}")
void updateUser(User user);
@Delete("delete from user where id=#{id}")
void deleteUser(Integer id);
@Select("select * from user where id=#{id}")
User findUserByUid(Integer id);