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

目录

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

Mybatis基础回顾与高级应用 数据库:mysql5.7
jdk:15

引入依赖
org.mybatismybatis3.4.5mysqlmysql-connector-java5.1.6runtimejunitjunit4.12org.projectlomboklombok1.18.22

User实体
@Datapublic class User {private Integer id; private String username; }


jdbc.properties
jdbc.driver=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://127.0.0.1/zdy_mybatisjdbc.username=rootjdbc.password=root


sqlMapConfig.xml
???


案例一-查询用户 UserMapper.xml
select * from user

@Testpublic 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 删除:deleteList 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})

@Testpublic 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(); }

数据库结果:
Mybatis基础概念与高级应用小结
文章图片


案例三-编辑用户
UserMapper.xml
update user set username = #{username} where id = #{id}

@Testpublic 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(); }

数据库结果:
Mybatis基础概念与高级应用小结
文章图片


案例四-删除用户
UserMapper.xml
delete from user where id =#{id}

@Testpublic 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(); ?}

数据库结果:
Mybatis基础概念与高级应用小结
文章图片


传统开发方式
public interface IUserDao {?//查询所有用户List findAll() throws IOException; }

UserDaoImpl
public class UserDaoImpl implements IUserDao {?@Overridepublic 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; }}

@Testpublic 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; }

@Testpublic 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 {?//多条件组合查询:演示ifpublic List findByCondition(User user); }

select * from user?and id = #{id}and username = #{username}

@Testpublic 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 {?//多值查询:演示foreachpublic List findByIds(int[] ids); }

#{id}

@Testpublic 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实体
@Datapublic class User {?private Integer id; ?private String username; ?//该用户所具有的订单信息private List orders; ?//该用户所具有的角色信息private List roles; }

Order实体
@Datapublic class Order {?private Integer id; ?private String orderTime; ?private BigDecimal total; ?//表明该订单属于哪个用户private User user; }

Role实体
@Datapublic class Role {?private Integer id; ?private String roleName; }

public interface IOrderMapper {?/*** 查询订单的同时还查询该订单所属的用户* @return*/public List findOrderAndUser(); }

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

@Testpublic void test1() throws IOException {//1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml"); //2.解析了配置文件,并创建了sqlSessionFactory工厂SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //3.生产sqlSessionSqlSession 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

@Testpublic void test2() throws IOException {//1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml"); //2.解析了配置文件,并创建了sqlSessionFactory工厂SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //3.生产sqlSessionSqlSession 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 uLEFT JOIN sys_user_role sur ON u.id = sur.user_idLEFT JOIN sys_role sr ON sur.role_id = sr.id

@Testpublic void test3() throws IOException {//1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml"); //2.解析了配置文件,并创建了sqlSessionFactory工厂SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //3.生产sqlSessionSqlSession 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; ?@Beforepublic void before() throws IOException {//1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml"); //2.解析了配置文件,并创建了sqlSessionFactory工厂SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //3.生产sqlSessiontrue:事务自动提交SqlSession sqlSession = sqlSessionFactory.openSession(true); mapper = sqlSession.getMapper(IUserMapper.class); }?@Testpublic void addUser(){User user = new User(); user.setId(3); user.setUsername("jack"); mapper.addUser(user); }?@Testpublic void updateUser(){User user = new User(); user.setId(3); user.setUsername("rose"); mapper.updateUser(user); }?@Testpublic void getAllUser(){List userList = mapper.getAllUser(); userList.forEach(item -> {System.out.println(item); }); }?@Testpublic void delUser(){mapper.delUser(3); }

运行结果:
Mybatis基础概念与高级应用小结
文章图片


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); }

@Testpublic 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); }

@Testpublic 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); }

@Testpublic 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缓存
基础概念
Mybatis基础概念与高级应用小结
文章图片

缓存就是内存中的数据,常常来自对数据库查询结果的保存,使用缓存,我们可以避免频繁的与数据库进行交互,进而提高响应速度.
一级缓存是SqlSession,在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据.不同的sqlSession之间互不影响.
二级缓存是mapper级别的缓存,多个sqlSession去操作同一个mapper的sql语句,多个sqlSession可以共用二级缓存,二级缓存是跨sqlSession的.

一级缓存
demo
public class CacheTest {?private IUserMapper mapper; private SqlSession sqlSession; ?@Beforepublic void before() throws IOException {//1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml"); //2.解析了配置文件,并创建了sqlSessionFactory工厂SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //3.生产sqlSessiontrue:事务自动提交sqlSession = sqlSessionFactory.openSession(true); mapper = sqlSession.getMapper(IUserMapper.class); }?@Testpublic 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; ?@Beforepublic void before() throws IOException {//1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml"); //2.解析了配置文件,并创建了sqlSessionFactory工厂SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //3.生产sqlSessiontrue:事务自动提交sqlSession = sqlSessionFactory.openSession(); mapper = sqlSession.getMapper(IUserMapper.class); }?@Testpublic 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查询到的数据也将存在相同的二级缓存区域中.
Mybatis基础概念与高级应用小结
文章图片


如何使用二级缓存 首先在全局配置文件sqlMapconfig.xml文件加入如下代码

注意,该配置需要放在properties标签下,具体顺序,可百度了解
其次,在xxxMapper.xml文件中开启缓存(如果当前操作时基于注解开发的话,使用注解@CacheNamespace)

demo2
public class CacheTest {?private IUserMapper mapper; private SqlSession sqlSession; private SqlSessionFactory sqlSessionFactory; ?@Beforepublic void before() throws IOException {//1.Resources工具类,配置文件的加载,把配置文件加载成字节输入流InputStream inputStream = Resources.getResourceAsStream("sqlMApConfig.xml"); //2.解析了配置文件,并创建了sqlSessionFactory工厂sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //3.生产sqlSessionsqlSession = sqlSessionFactory.openSession(); mapper = sqlSession.getMapper(IUserMapper.class); }?@Testpublic 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 user2 = mapper2.getUserById(1); ?System.out.println(user1 == user2); }}

运行结果为 false
结论:通过debug断点显示,实际上,第二次查询则会直接从缓存中获取用户信息了,不过二级缓存缓存的不是对象,而是缓存的对象中的数据,所以查询结果为false;
注意,二级缓存底层还是HashMap结构,所以 po类需要实现序列化接口 ; 因为二级缓存数据存储介质多种多样,不一定只存在内存中,有可能存在硬盘中,如果我们要在取这个缓存的话,就需要反序列化了,所以mybatis中的pojo都去实现Serializable接口;
变换一下demo2
@Testpublic 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基础概念及应用回顾完成!
【Mybatis基础概念与高级应用小结】到此这篇关于Mybatis基础回顾与高级应用的文章就介绍到这了,更多相关Mybatis高级应用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

    推荐阅读