Mybatis基础概念与高级应用小结

网友投稿 576 2022-09-29

Mybatis基础概念与高级应用小结

Mybatis基础概念与高级应用小结

目录Mybatis基础回顾与高级应用引入依赖jdbc.propertiessqlMapConfig.xml案例一-查询用户案例二-添加用户案例三-编辑用户案例四-删除用户传统开发方式代理开发方式(使用JDK动态代理产生代理对象,由代理对象执行并且操作)动态sql语句 if标签Mybatis复杂映射一对一一对多多对多Mybatis注解开发Mybatis注解实现复杂映射开发Mybatis缓存基础概念一级缓存返回结果为 true ;测试一级缓存是默认开启的返回结果为 false二级缓存如何使用二级缓存返回结果为 false

Mybatis基础回顾与高级应用

数据库:mysql5.7

jdk:15

引入依赖

org.mybatis

mybatis

3.4.5

mysql

mysql-connector-java

5.1.6

runtime

junit

junit

4.12

org.projectlombok

lombok

1.18.22

User实体

@Data

public class User {

private Integer id;

private String username;

}

jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://127.0.0.1/zdy_mybatis

jdbc.username=root

jdbc.password=root

sqlMapConfig.xml

"http://mybatis.org/dtd/mybatis-3-config.dtd">

http://

案例一-查询用户

UserMapper.xml

select * from user

@Test

public void test1() throws IOException {

//1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流

InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");

//2.解析了配置文件,并创建了sqlSessionFactory工厂

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

//3.生产sqlSession

// 默认开启一个事务,但是该事务不会自动提交

//在进行增删改操作时,要手动提交事务

SqlSession sqlSession = sqlSessionFactory.openSession();

//4.sqlSession调用方法:查询所有selectList 查询单个:selectOne 添加:insert 修改:update 删除:delete

List users = sqlSession.selectList("user.findAll");

users.forEach(item ->{

System.out.println(item);

});

sqlSession.close();

}

输出结果

User(id=1, username=Tom)User(id=2, username=Jerry)

案例二-添加用户

UserMapper.xml

insert into user Values (#{id},#{username})

@Test

public void test2() throws IOException {

InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

SqlSession sqlSession = sqlSessionFactory.openSession();

User user = new User();

user.setId(3);

user.setUsername("jack");

sqlSession.insert("user.saveUser",user);

sqlSession.commit();

sqlSession.close();

}

数据库结果:

案例三-编辑用户

UserMapper.xml

update user set username = #{username} where id = #{id}

@Test

public void test3() throws IOException {

InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

SqlSession sqlSession = sqlSessionFactory.openSession();

User user = new User();

user.setId(3);

user.setUsername("rose");

sqlSession.update("user.updateUser",user);

sqlSession.commit();

sqlSession.close();

}

数据库结果:

案例四-删除用户

UserMapper.xml

delete from user where id =#{id}

@Test

public void test4() throws IOException {

InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

SqlSession sqlSession = sqlSessionFactory.openSession();

User user = new User();

user.setId(3);

sqlSession.delete("user.deleteUser",3);

sqlSession.commit();

sqlSession.close();

}

数据库结果:

传统开发方式

public interface IUserDao {

//查询所有用户

List findAll() throws IOException;

}

UserDaoImpl

public class UserDaoImpl implements IUserDao {

@Override

public List findAll() throws IOException {

InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

SqlSession sqlSession = sqlSessionFactory.openSession();

List users = sqlSession.selectList("user.findAll");

sqlSession.close();

return users;

}

}

@Test

public void test5() throws IOException {

UserDaoImpl dao = new UserDaoImpl();

List users = dao.findAll();

System.out.println(users);

}

打印结果:

[User(id=1, username=Tom), User(id=2, username=Jerry)]

代理开发方式(使用JDK动态代理产生代理对象,由代理对象执行并且操作)

Mapper接口开发需要遵行以下规范:

mapper.xml文件中的namespace与mapper接口的全限定名相同;2. mapper接口方法名和mapper.xml中定义的每个statement的id相同3. mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同4. mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

根据上述的规范修改UserMapper.xml

select * from user

public interface IUserDao {

//查询所有用户

List findAll() throws IOException;

}

@Test

public void test6() throws IOException {

InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);

SqlSession sqlSession = sqlSessionFactory.openSession();

IUserDao mapper = sqlSession.getMapper(IUserDao.class);

List all = mapper.findAll();

all.forEach(item ->{

System.out.println(all);

});

}

输出结果:

User(id=1, username=Tom)User(id=2, username=Jerry)

动态sql语句 if标签

public interface IUserDao {

//多条件组合查询:演示if

public List findByCondition(User user);

}

select * from user

and id = #{id}

and username = #{username}

@Test

public void test7() throws IOException {

InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);

SqlSession sqlSession = sqlSessionFactory.openSession();

IUserDao mapper = sqlSession.getMapper(IUserDao.class);

User user1 = new User();

user1.setId(1);

user1.setUsername("Tom");

List all = mapper.findByCondition(user1);

for (User user : all) {

System.out.println(user);

}

}

输出结果:

User(id=1, username=Tom)

动态sql语句 foreach标签

public interface IUserDao {

//多值查询:演示foreach

public List findByIds(int[] ids);

}

#{id}

@Test

public void test8() throws IOException {

InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);

SqlSession sqlSession = sqlSessionFactory.openSession();

IUserDao mapper = sqlSession.getMapper(IUserDao.class);

int[] arr = {1,2};

List all = mapper.findByIds(arr);

for (User user : all) {

System.out.println(user);

}

}

输出结果:

User(id=1, username=Tom)User(id=2, username=Jerry)

Mybatis复杂映射

一对一

User实体

@Data

public class User {

private Integer id;

private String username;

//该用户所具有的订单信息

private List orders;

//该用户所具有的角色信息

private List roles;

}

Order实体

@Data

public class Order {

private Integer id;

private String orderTime;

private BigDecimal total;

//表明该订单属于哪个用户

private User user;

}

Role实体

@Data

public class Role {

private Integer id;

private String roleName;

}

public interface IOrderMapper {

/**

* 查询订单的同时还查询该订单所属的用户

* @return

*/

public List findOrderAndUser();

}

select * from orders o,user u where o.uid = u.id

@Test

public void test1() throws IOException {

//1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流

InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");

//2.解析了配置文件,并创建了sqlSessionFactory工厂

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

//3.生产sqlSession

SqlSession sqlSession = sqlSessionFactory.openSession();

IOrderMapper mapper = sqlSession.getMapper(IOrderMapper.class);

List orderAndUser = mapper.findOrderAndUser();

orderAndUser.forEach(order -> {

System.out.println(order);

});

}

运行结果:

Order(id=1, orderTime=2022-05-01, total=1000.00, user=User(id=1, username=Tom, orders=null, roles=null))Order(id=2, orderTime=2022-05-10, total=2000.00, user=User(id=2, username=Jerry, orders=null, roles=null))Order(id=3, orderTime=2022-05-20, total=3000.00, user=User(id=2, username=Jerry, orders=null, roles=null))

一对多

public interface IUserMapper {

/**

* 查询所有用户信息,同时查询出每个用户关联的订单信息

* @return

*/

public List findAll();

}

select u.*,o.id oid,o.order_time,o.total,o.uid from user u left join orders o on u.id = o.uid

@Test

public void test2() throws IOException {

//1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流

InputStream inputStream = Resources.getRaycvxuoFesourceAsStream("sqlMApConfig.xml");

//2.解析了配置文件,并创建了sqlSessionFactory工厂

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

//3.生产sqlSession

SqlSession sqlSession = sqlSessionFactory.openSession();

IUserMapper mapper = sqlSession.getMapper(IUserMapper.class);

List users = mapper.findAll();

users.forEach(user -> {

System.out.println(user.getUsername());

System.out.println(user.getOrders());

});

}

运行结果:

Tom[Order(id=1, orderTime=2022-05-01, total=1000.00, user=null)]Jerry[Order(id=2, orderTime=2022-05-10, total=2000.00, user=null), Order(id=3, orderTime=2022-05-20, total=3000.00, user=null)]

多对多

public interface IUserMapper {

/**

* 查询所有用户信息,同事查询出每个用户关联的角色信息

* @return

*/

public List findUserAndRole();

}

SELECT * FROM USER u

LEFT JOIN sys_user_role sur ON u.id = sur.user_id

LEFT JOIN sys_role sr ON sur.role_id = sr.id

@Test

public void test3() throws IOException {

//1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流

InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");

//2.解析了配置文件,并创建了sqlSessionFactory工厂

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

//3.生产sqlSession

SqlSession sqlSession = sqlSessionFactory.openSession();

IUserMapper mapper = sqlSession.getMapper(IUserMapper.class);

List users = mapper.findUserAndRole();

users.forEach(user -> {

System.out.println(user.getUsername());

System.out.println(user.getRoles());

});

}

运行结果:

Tom[Role(id=null, roleName=董事长), Role(id=null, roleName=经理)]Jerry[Role(id=null, roleName=董事长), Role(id=null, roleName=经理)]

Mybatis注解开发

Mybasits常用注解:

@Insert: 实现新增

@Update: 实现更新

@Delete: 实现删除

@Select: 实现查询

@Result: 实现结果集封装;他代替的是标签,该注解中可以使用单个@Result注解,也可以使用@Result集合,

使用格式:@Results({@Result(),@Result()}) 或 @Results(@Result())

@Results: 可以与@Result一起使用,封装多个结果集

@One: 实现一对一结果集封装

@Many: 实现一对多结果集封装

测试案例

public interface IUserMapper {

//添加用户

@Insert("insert into user values(#{id},#{username})")

public void addUser(User user);

//更新用户

@Update("update user set username = #{} where id = #{id}")

public void updateUser(User user);

//查询用户

@Select("select * from user")

public List getAllUser();

//删除用户

@Delete("delete from user where id=#{id}")

public void delUser(Integer id);

}

private IUserMapper mapper;

@Before

public void before() throws IOException {

//1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流

InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");

//2.解析了配置文件,并创建了sqlSessionFactory工厂

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

//3.生产sqlSession true:事务自动提交

SqlSession sqlSession = sqlSessionFactory.openSession(true);

mapper = sqlSession.getMapper(IUserMapper.class);

}

@Test

public void addUser(){

User user = new User();

user.setId(3);

user.setUsername("jack");

mapper.addUser(user);

}

@Test

public void updateUser(){

User user = new User();

user.setId(3);

user.setUsername("rose");

mapper.updateUser(user);

}

@Test

public void getAllUser(){

List userList = mapper.getAllUser();

userList.forEach(item -> {

System.out.println(item);

});

}

@Test

public void delUser(){

mapper.delUser(3);

}

运行结果:

Mybatis注解实现复杂映射开发

一对一

public interface IOrderMapper {

/**

* 查询订单的同时还查询该订单所属的用户

* @return

*/

@Results({

@Result(property = "id",column = "id"),

@Result(property = "orderTime",column = "order_time"),

@Result(property = "total",column = "total"),

@Result(property = "user",column = "uid",javaType = User.class,

one = @One(select = "com.yun.mapper.IUserMapper.getUserById")),

})

@Select("select * from orders")

public List findOrderAndUser();

}

public interface IUserMapper {

@Select("select * from user where id = #{id}")

public User getUserById(Integer id);

}

@Test

public void oneToOne(){

List orderAndUser = orderMapper.findOrderAndUser();

orderAndUser.forEach(item -> {

System.out.println(item);

});

}

运行结果:

Order(id=1, orderTime=2022-05-01, total=1000.00, user=User(id=1, username=Tom, orders=null, roles=null))Order(id=2, orderTime=2022-05-10, total=2000.00, user=User(id=2, username=Jerry, orders=null, roles=null))Order(id=3, orderTime=2022-05-20, total=3000.00, user=User(id=2, username=Jerry, orders=null, roles=null))

一对多

public interface IUserMapper {

/**

* 查询所有用户信息,同时查询出每个用户关联的订单信息

* @return

*/

@Select("select * from user")

@Results({

@Result(property = "id",column = "id"),

@Result(property = "username",column = "username"),

@Result(property = "orders",column = "id",javaType = List.class,

many = @Many(select = "com.yun.mapper.IOrderMapper.getOrderByUid"))

})

public List findAll();

}

public interface IOrderMapper {

@Select("select * from orders where uid = #{uid}")

public List getOrderByUid(Integer uid);

}

@Test

public void oneToMore(){

List users = mapper.findAll();

users.forEach(item -> {

System.out.println(item);

});

}

运行结果:

User(id=1, username=Tom, orders=[Order(id=1, orderTime=null, total=1000.00, user=null)], roles=null)User(id=2, username=Jerry, orders=[Order(id=2, orderTime=null, total=2000.00, user=null), Order(id=3, orderTime=null, total=3000.00, user=null)], roles=null)

多对多

public interface IUserMapper {

/**

* 查询所有用户信息,同事查询出每个用户关联的角色信息

* @return

*/

@Select("select * from user")

@Results({

@Result(property = "id",column = "id"),

@Result(property = "username",column = "username"),

@Result(property = "roles",column = "id",javaType = List.class,

many = @Many(select ="com.yun.mapper.IRoleMapper.getAll"))

})

public List findUserAndRole();

}

public interface IRoleMapper {

@Select("select * from sys_role sr,sys_user_role sur where sr.id = sur.role_id and sur.user_id = #{uid}")

public List getAll(Integer uid);

}

@Test

public void moreToMore(){

List users = mapper.findUserAndRole();

users.forEach(item -> {

System.out.println(item);

});

}

运行结果:

User(id=1, username=Tom, orders=null, roles=[Role(id=1, roleName=董事长), Role(id=2, roleName=经理)])User(id=2, username=Jerry, orders=null, roles=[Role(id=1, roleName=董事长), Role(id=2, roleName=经理)])

Mybatis缓存

基础概念

缓存就是内存中的数据,常常来自对数据库查询结果的保存,使用缓存,我们可以避免频繁的与数据库进行交互,进而提高响应速度.

一级缓存是SqlSession,在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据.不同的sqlSession之间互不影响.

二级缓存是mapper级别的缓存,多个sqlSession去操作同一个mapper的sql语句,多个sqlSession可以共用二级缓存,二级缓存是跨sqlSession的.

一级缓存

demo

public class CacheTest {

private IUserMapper mapper;

private SqlSession sqlSession;

@Before

public void before() throws IOException {

//1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流

InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");

//2.解析了配置文件,并创建了sqlSessionFactory工厂

SqlSessionFactory sqlSessionFactory = new SqlSessionFachttp://toryBuilder().build(inputStream);

//3.生产sqlSession true:事务自动提交

sqlSession = sqlSessionFactory.openSession(true);

mapper = sqlSession.getMapper(IUserMapper.class);

}

@Test

public void test1() {

//第一次查询id为1的用户

User user1 = mapper.getUserById(1);

//第二次查询id为1的用户

User user2 = mapper.getUserById(1);

System.out.println(user1 == user2);

}

}

返回结果为 true ;测试一级缓存是默认开启的

结论:第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户,如果没有,则从数据库查询用户信息,得到用户信息并且将用户信息存储到一级缓存中,第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户,如果缓存中有,直接从缓存中获取用户信息;

现在我们变换一下上面的demo

public class CacheTest {

private IUserMapper mapper;

private SqlSession sqlSession;

@Before

public void before() throws IOException {

//1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流

InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");

//2.解析了配置文件,并创建了sqlSessionFactory工厂

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

//3.生产sqlSession true:事务自动提交

sqlSession = sqlSessionFactory.openSession();

mapper = sqlSession.getMapper(IUserMapper.class);

}

@Test

public void test1() {

//第一次查询id为1的用户

User user1 = mapper.getUserById(1);

User user = new User();

user.setId(1);

user.setUsername("Lucy");

mapper.updateUser(user);

sqlSession.commit();

//第二次查询id为1的用户

User user2 = mapper.getUserById(1);

System.out.println(user1 == user2);

}

}

返回结果为 false

结论:做增删改操作,并进行了事物的提交,就会刷新以及缓存;或者还可以通过 sqlSession.clearCache()清楚缓存;这样做的目的就是为了让缓存中存储的是最新的信息,避免脏读;

二级缓存

二级缓存的原理和一级缓存原理一样,第一次查询会将数据放入缓存中,然后第二次查询则会直接从缓存中获取,但是一级缓存是基于sqlSession的,而二级缓存是基于mapper文件的namespace,也就是说,多个sqlSession可以共享一个mapper中的二级缓存,并且如果两个mapper的namespace相同,即使是两个mapper,那么这两个mapper执行sql查询到的数据也将存在相同的二级缓存区域中.

如何使用二级缓存

首先在全局配置文件sqlMapconfig.xml文件加入如下代码

注意,该配置需要放在properties标签下,具体顺序,可百度了解

其次,在xxxMapper.xml文件中开启缓存(如果当前操作时基于注解开发的话,使用注解@CacheNamespace)

demo2

public class CacheTest {

private IUserMapper mapper;

private SqlSession sqlSession;

private SqlSessionFactory sqlSessionFactory;

@Before

public void before() throws IOException {

//1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流

InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml");

//2.解析了配置文件,并创建了sqlSessionFactory工厂

sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

//3.生产sqlSession

sqlSession = sqlSessionFactory.openSession();

mapper = sqlSession.getMapper(IUserMapper.class);

}

@Test

public void test2() {

SqlSession sqlSession1 = sqlSessionFactory.openSession();

SqlSession sqlSession2 = sqlSessionFactory.openSession();

SqlSession sqlSession3 = sqlSessionFactory.openSession();

IUserMapper mapper1 = sqlSession1.getMapper(IUserMapper.class);

IUserMapper mapper2 = sqlSession2.getMapper(IUserMapper.class);

IUserMapper mapper3 = sqlSession3.getMapper(IUserMapper.class);

User user1http:// = mapper1.getUserById(1);

//清空一级缓存

sqlSession1.close();

User user2 = mapper2.getUserById(1);

System.out.println(user1 == user2);

}

}

运行结果为 false

结论:通过debug断点显示,实际上,第二次查询则会直接从缓存中获取用户信息了,不过二级缓存缓存的不是对象,而是缓存的对象中的数据,所以查询结果为false;

注意,二级缓存底层还是HashMap结构,所以 po类需要实现序列化接口 ;因为二级缓存数据存储介质多种多样,不一定只存在内存中,有可能存在硬盘中,如果我们要在取这个缓存的话,就需要反序列化了,所以mybatis中的pojo都去实现Serializable接口;

变换一下demo2

@Test

public void test2() {

SqlSession sqlSession1 = sqlSessionFactory.openSession();

SqlSession sqlSession2 = sqlSessionFactory.openSession();

SqlSession sqlSession3 = sqlSessionFactory.openSession();

IUserMapper mapper1 = sqlSession1.getMapper(IUserMapper.class);

IUserMapper mapper2 = sqlSession2.getMapper(IUserMapper.class);

IUserMapper mapper3 = sqlSession3.getMapper(IUserMapper.class);

User user1 = mapper1.getUserById(1);

//清空一级缓存

sqlSession1.close();

User user = new User();

user.setId(1);

user.setUsername("Tom");

mapper3.updateUser(user);

sqlSession3.commit();

User user2 = mapper2.getUserById(1);

System.out.println(user1 == user2);

}

返回结果为 false

结论:做增删改操作,并进行了事物的提交,就会刷新以及缓存;这样做的目的就是为了让缓存中存储的是最新的信息,避免脏读;

此外mybatis中还可以配置useCache和flushCache等配置项;

useCache

是用来设置是否禁用二级缓存的,在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会会发出sql去查询,默认情况是true,即该sql使用二级缓存,例如

select u.*,o.id oid,o.order_time,o.total,o.uid from user u left join orders o on u.id = o.uid

使用sql注解方式可以使用@Options(useCache = false)的方式

flushCache

在mapper的同一个namespace中,如果有其他的insert,update,delete操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读,设置statememt配置中的

flushCache = "true"属性,默认情况下为true,即刷新缓存,如果改成false则不会刷新,使用缓存时如果手动修改数据库表中的查询数据会出现脏读 例如

select u.*,o.id oid,o.order_time,o.total,o.uid from user u left join orders o on u.id = o.uid

一般下执行完commit操作都需要刷新缓存,flushCache=true表示刷新缓存,这样可以避免数据库脏读,所以我们不用设置,默认即可

至此,mybatis基础概念及应用回顾完成!

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:操作系统学习笔记:死锁
下一篇:操作系统学习笔记:CPU调度
相关文章

 发表评论

暂时没有评论,来抢沙发吧~