小言_互联网的博客

JavaWeb——MyBatis框架之对数据库的增删改查操作CRUD实践及MyBatis参数的深入详解

400人阅读  评论(0)

目录

1 使用MyBatis对数据库的增删改查操作

1.1 保存操作

1.2 修改操作

1.3 删除操作

1.4 查询操作

2 MyBatis中参数的深入详解

2.1 实体类包装对象作为查询条件

2.2 实体类属性和数据库列名不对应的解决


本博文总结下使用MyBatis的CRUD操作及参数的深入,关于MyBatis的环境搭建就不再赘述了,可以回顾下以前的博文,本次也是在这个工厂的基础上进行的。

1 使用MyBatis对数据库的增删改查操作

1.1 保存操作

需求:保存一个用户对象,并获取保存数据的id值。

1)UserDao接口中定义好保存操作方法


   
  1. //用户持久层接口
  2. public interface UserDao {
  3. //保存用户
  4. void saveUser(User user);
  5. }

2)映射配置文件中增加配置


   
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.winter.dao.UserDao">
  6. <!-- 保存用户-->
  7. <insert id="saveUser" parameterType="com.winter.domain.User">
  8. -- 配置插入后获取插入数据的id
  9. <selectKey keyProperty="id" keyColumn="id" resultType="Integer" order="AFTER">
  10. select last_insert_id();
  11. </selectKey>
  12. insert into user(username,address,sex,birthday) values(#{username},#{address},#{sex},#{birthday});
  13. </insert>
  14. </mapper>

【注意】:

  • parameterType属性,代表的是参数的类型,我们写要传入类的全名称;
  • sql中用#{}表示占位符,类似于前面学习JDBC中的?,用来替换实际的数据;

3)添加测试类中的保存测试方法

【注意】:

  • 获取dao代理对象和释放资源封装在了两个方法中,并通过@before和@after注解执行;
  • 在释放资源方法中,释放资源前要进行commit事务提交,因为其默认是手动提交的,否则执行保存用户方法后不会插入数据;
  • 关于执行testSave方法后插入了两条数据,怀疑是使用maven构建,此处又使用@Test运行,可能是运行了两次导致实际插入两次数据,在File-Settings-Maven-Runner 中勾选skip Tests即可解决。

   
  1. //测试MyBatis的CRUD
  2. public class MyBatisTest {
  3. private InputStream in;
  4. private SqlSession sqlSession;
  5. private UserDao userDao;
  6. @Before //在测试方法执行前执行
  7. public void init() throws Exception{
  8. //1、读取配置文件,生成字节输入流
  9. in = Resources.getResourceAsStream( "SqlMapConfig.xml");
  10. //2、获取SqlSessionFactory
  11. SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
  12. //3、获取SqlSession对象
  13. sqlSession = factory.openSession();
  14. //4、获取dao的代理对象
  15. userDao = sqlSession.getMapper(UserDao.class);
  16. }
  17. @After //测试方法执行后执行
  18. public void destroy() throws Exception{
  19. //提交事务
  20. sqlSession.commit();
  21. //6、释放资源
  22. sqlSession.close();
  23. in.close();
  24. }
  25. //测试保存
  26. @Test
  27. public void testSave(){
  28. User user = new User();
  29. user.setUsername( "MyBatis new insert");
  30. user.setAddress( "BJ");
  31. user.setSex( "男");
  32. user.setBirthday( new Date());
  33. System.out.println( "保存前:"+user);
  34. //5.执行保存方法
  35. userDao.saveUser(user);
  36. System.out.println( "保存后:"+user);
  37. }
  38. }

1.2 修改操作

1)UserDao接口中定义好修改操作方法


   
  1. //用户持久层接口
  2. public interface UserDao {
  3. //修改用户
  4. void updateUser(User user);
  5. }

2)映射配置文件中增加配置


   
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.winter.dao.UserDao">
  6. <!-- 修改用户-->
  7. <update id="updateUser" parameterType="com.winter.domain.User">
  8. update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where id=#{id};
  9. </update>
  10. </mapper>

3)添加测试类中的保存测试方法


   
  1. //测试修改
  2. @Test
  3. public void testUpdate(){
  4. User user = new User();
  5. user.setId( 25);
  6. user.setUsername( "MyBatis_Update");
  7. user.setAddress( "DQ");
  8. user.setSex( "女");
  9. user.setBirthday( new Date());
  10. //5.执行修改方法
  11. userDao.updateUser(user);
  12. }

1.3 删除操作

1)UserDao接口中定义好删除操作方法


   
  1. //用户持久层接口
  2. public interface UserDao {
  3. //删除用户,根据ID
  4. void deleteUser(Integer userId);
  5. }

2)映射配置文件中增加配置


   
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.winter.dao.UserDao">
  6. <!-- 删除用户-->
  7. <delete id="deleteUser" parameterType="Integer">
  8. delete from user where id = #{userId}
  9. </delete>
  10. </mapper>

3)添加测试类中的删除测试方法


   
  1. //测试删除
  2. @Test
  3. public void testDelete(){
  4. //5.执行删除方法
  5. userDao.deleteUser( 24);
  6. }

1.4 查询操作

这里实现两个功能,一个根据id查询用户,另一个是根据名字模糊查询。
 
1)UserDao接口中定义好查询操作方法

  
  1. //用户持久层接口
  2. public interface UserDao {
  3. //根据id查询用户
  4. User findById(Integer userId);
  5. //模糊查询
  6. List<User> findByName(String username);
  7. }

2)映射配置文件中增加配置

3)添加测试类中的查询测试方法


  
  1. //测试查询一个用户
  2. @Test
  3. public void testFindById(){
  4. //5.执行查询
  5. User user = userDao.findById( 25);
  6. System.out.println(user); //User{id=25, username='MyBatis_Update', address='DQ', sex='女', birthday=Mon Sep 14 17:01:09 CST 2020}
  7. }
  8. //测试模糊查询
  9. @Test
  10. public void testFindByName(){
  11. //5.执行查询
  12. List<User> users = userDao.findByName( "%王%");
  13. for (User user : users) {
  14. System.out.println(user);
  15. }
  16. }

【注意】:模糊查询还有另外一种配置方式,对应的测试类中的方法参数也要变更,去掉%


  
  1. <select id="findByName" parameterType="String" resultType="com.winter.domain.User">
  2. <!--select *from user where username like #{username}-->
  3. select *from user where username like '%${value}%'
  4. </select>

  
  1. //5.执行查询
  2. // List<User> users = userDao.findByName("%王%");
  3. List<User> users = userDao.findByName( "王");

这种配置方式,value名字是固定的,不能改为其他的,且这种相对于前一种,虽然效果一样,但是执行的sql语句不同:

由此,我们可以发现,#{}用的是PreparedStatement的参数占位符,可以有效防止sql注入问题,而${}用的是Statement对象的字符串拼接SQL。实际开发中我们使用#{}比较靠谱。

2 MyBatis中参数的深入详解

2.1 实体类包装对象作为查询条件

首先了解下ognl表达式,MyBatis使用ognl表达式解析对象字段的值,什么是ognl表达式?

  • OGNL表达式,是Apache开发的,全称为Object Graphic Navigation Language,对象图导航语言;
  • 它通过对象的取值方法来获取数据,在写法上把get给省略了,比如获取对象名称,类写法:user.getUsername(),OGNL表达式的写法:user.username。MyBatis中之所以能直接写username,而不是user.username,是因为在parameterType中已经提供了属性所属的类。

我们在第一部分的内容,查询条件都比较单一,若是比较综合的查询,需要把查询条件封装一个对象传递,这时该怎么做?还是举个栗子说明具体实现步骤吧:

1)UserDao接口中定义好查询操作方法findUserByVo


  
  1. //用户持久层接口
  2. public interface UserDao {
  3. //根据QueryVo查询条件查询用户
  4. List<User> findUserByVo(QueryVo vo);
  5. }

2)映射配置文件中增加配置


  
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.winter.dao.UserDao">
  6. <!-- 根据QueryVo条件查询用户-->
  7. <select id="findUserByVo" parameterType="com.winter.domain.QueryVo" resultType="com.winter.domain.User">
  8. select *from user where username like #{user.username}
  9. </select>
  10. </mapper>

3)添加测试类中的查询测试方法


  
  1. //测试使用QueryVo作为查询条件
  2. @Test
  3. public void testFindUserByVo(){
  4. QueryVo vo = new QueryVo();
  5. User user = new User();
  6. user.setUsername( "%王%");
  7. vo.setUser(user);
  8. //5.执行查询
  9. List<User> users = userDao.findUserByVo(vo);
  10. for (User user1 : users) {
  11. System.out.println(user1);
  12. }
  13. }

2.2 实体类属性和数据库列名不对应的解决

我们前面的练习都是让实体类属性和数据库列名严格保持一致的(这里注意,MySQL在windows下是不区分大小写的,即把userName写成username,windows环境下都认为是一样的,但是在Linux环境下是严格区分大小写的),不保持一致是不能进行增删改查操作的,但是不对应的情况下有没有办法解决呢?

【方法一】:起别名,效率是最高的,在SQL语句层面上解决的

比如,你的数据库列名为id、username、address、sex,而你的类属性名为userId、userName、userAddress、userSex,此时在映射配置文件中可以这么写:


  
  1. <!-- 查询所有-->
  2. <select id="findAll" resultType="com.winter.domain.User">
  3. select id as userId,username as userName,address as userAddress,sex as userSex from user;
  4. </select>

【方法二】:配置方式,使用resultMap配置实体类属性名和查询结果的列名对应关系,此时需要注意的查询所有对应的配置中resultType要换为resultMap,即resultMap="userMap"。这种方式开发效率高,但是多了一步解析,所以运行效率低了些。


  
  1. <!-- 查询所有-->
  2. <resultMap id="userMap" type="com.winter.domain.User">
  3. <!--主键字段 -->
  4. <id property="userId" column="id"> </id>
  5. <!--非主键字段 -->
  6. <result property="userName" column="name"> </result>
  7. <result property="userAddress" column="address"> </result>
  8. <result property="userSex" column="sex"> </result>
  9. </resultMap>
  10. <select id="findAll" resultType="com.winter.domain.User">
  11. select * from user;
  12. </select>

需要源码的传送门在此。

———————————————————————————————————

本文为博主原创文章,转载请注明出处!

若本文对您有帮助,轻抬您发财的小手,关注/评论/点赞/收藏,就是对我最大的支持!

祝君升职加薪,鹏程万里!


转载:https://blog.csdn.net/w464960660/article/details/108474469
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场