JavaWeb——MyBatis框架之对数据库的增删改查操作CRUD实践及MyBatis参数的深入详解
本博文总结下使用MyBatis的CRUD操作及参数的深入,关于MyBatis的环境搭建就不再赘述了,可以回顾下以前的博文,本次也是在这个工厂的基础上进行的。
1 使用MyBatis对数据库的增删改查操作
1.1 保存操作
需求:保存一个用户对象,并获取保存数据的id值。
1)UserDao接口中定义好保存操作方法
//用户持久层接口
public interface UserDao {
//保存用户
void saveUser(User user);
}
2)映射配置文件中增加配置
<?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">
<mapper namespace="com.winter.dao.UserDao">
<!-- 保存用户-->
<insert id="saveUser" parameterType="com.winter.domain.User">
-- 配置插入后获取插入数据的id
<selectKey keyProperty="id" keyColumn="id" resultType="Integer" order="AFTER">
select last_insert_id();
</selectKey>
insert into user(username,address,sex,birthday) values(#{username},#{address},#{sex},#{birthday});
</insert>
</mapper>
【注意】:
- parameterType属性,代表的是参数的类型,我们写要传入类的全名称;
- sql中用#{}表示占位符,类似于前面学习JDBC中的?,用来替换实际的数据;
3)添加测试类中的保存测试方法
【注意】:
- 获取dao代理对象和释放资源封装在了两个方法中,并通过@before和@after注解执行;
- 在释放资源方法中,释放资源前要进行commit事务提交,因为其默认是手动提交的,否则执行保存用户方法后不会插入数据;
- 关于执行testSave方法后插入了两条数据,怀疑是使用maven构建,此处又使用@Test运行,可能是运行了两次导致实际插入两次数据,在File-Settings-Maven-Runner 中勾选skip Tests即可解决。
//测试MyBatis的CRUD
public class MyBatisTest {
private InputStream in;
private SqlSession sqlSession;
private UserDao userDao;
@Before //在测试方法执行前执行
public void init() throws Exception{
//1、读取配置文件,生成字节输入流
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2、获取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//3、获取SqlSession对象
sqlSession = factory.openSession();
//4、获取dao的代理对象
userDao = sqlSession.getMapper(UserDao.class);
}
@After //测试方法执行后执行
public void destroy() throws Exception{
//提交事务
sqlSession.commit();
//6、释放资源
sqlSession.close();
in.close();
}
//测试保存
@Test
public void testSave(){
User user = new User();
user.setUsername("MyBatis new insert");
user.setAddress("BJ");
user.setSex("男");
user.setBirthday(new Date());
System.out.println("保存前:"+user);
//5.执行保存方法
userDao.saveUser(user);
System.out.println("保存后:"+user);
}
}
1.2 修改操作
1)UserDao接口中定义好修改操作方法
//用户持久层接口
public interface UserDao {
//修改用户
void updateUser(User user);
}
2)映射配置文件中增加配置
<?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">
<mapper namespace="com.winter.dao.UserDao">
<!-- 修改用户-->
<update id="updateUser" parameterType="com.winter.domain.User">
update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where id=#{id};
</update>
</mapper>
3)添加测试类中的保存测试方法
//测试修改
@Test
public void testUpdate(){
User user = new User();
user.setId(25);
user.setUsername("MyBatis_Update");
user.setAddress("DQ");
user.setSex("女");
user.setBirthday(new Date());
//5.执行修改方法
userDao.updateUser(user);
}
1.3 删除操作
1)UserDao接口中定义好删除操作方法
//用户持久层接口
public interface UserDao {
//删除用户,根据ID
void deleteUser(Integer userId);
}
2)映射配置文件中增加配置
<?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">
<mapper namespace="com.winter.dao.UserDao">
<!-- 删除用户-->
<delete id="deleteUser" parameterType="Integer">
delete from user where id = #{userId}
</delete>
</mapper>
3)添加测试类中的删除测试方法
//测试删除
@Test
public void testDelete(){
//5.执行删除方法
userDao.deleteUser(24);
}
1.4 查询操作
这里实现两个功能,一个根据id查询用户,另一个是根据名字模糊查询。
1)UserDao接口中定义好查询操作方法
//用户持久层接口
public interface UserDao {
//根据id查询用户
User findById(Integer userId);
//模糊查询
List<User> findByName(String username);
}
2)映射配置文件中增加配置
3)添加测试类中的查询测试方法
//测试查询一个用户
@Test
public void testFindById(){
//5.执行查询
User user = userDao.findById(25);
System.out.println(user);//User{id=25, username='MyBatis_Update', address='DQ', sex='女', birthday=Mon Sep 14 17:01:09 CST 2020}
}
//测试模糊查询
@Test
public void testFindByName(){
//5.执行查询
List<User> users = userDao.findByName("%王%");
for (User user : users) {
System.out.println(user);
}
}
【注意】:模糊查询还有另外一种配置方式,对应的测试类中的方法参数也要变更,去掉%
<select id="findByName" parameterType="String" resultType="com.winter.domain.User">
<!--select *from user where username like #{username}-->
select *from user where username like '%${value}%'
</select>
//5.执行查询
// List<User> users = userDao.findByName("%王%");
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
//用户持久层接口
public interface UserDao {
//根据QueryVo查询条件查询用户
List<User> findUserByVo(QueryVo vo);
}
2)映射配置文件中增加配置
<?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">
<mapper namespace="com.winter.dao.UserDao">
<!-- 根据QueryVo条件查询用户-->
<select id="findUserByVo" parameterType="com.winter.domain.QueryVo" resultType="com.winter.domain.User">
select *from user where username like #{user.username}
</select>
</mapper>
3)添加测试类中的查询测试方法
//测试使用QueryVo作为查询条件
@Test
public void testFindUserByVo(){
QueryVo vo = new QueryVo();
User user = new User();
user.setUsername("%王%");
vo.setUser(user);
//5.执行查询
List<User> users = userDao.findUserByVo(vo);
for (User user1 : users) {
System.out.println(user1);
}
}
2.2 实体类属性和数据库列名不对应的解决
我们前面的练习都是让实体类属性和数据库列名严格保持一致的(这里注意,MySQL在windows下是不区分大小写的,即把userName写成username,windows环境下都认为是一样的,但是在Linux环境下是严格区分大小写的),不保持一致是不能进行增删改查操作的,但是不对应的情况下有没有办法解决呢?
【方法一】:起别名,效率是最高的,在SQL语句层面上解决的
比如,你的数据库列名为id、username、address、sex,而你的类属性名为userId、userName、userAddress、userSex,此时在映射配置文件中可以这么写:
<!-- 查询所有-->
<select id="findAll" resultType="com.winter.domain.User">
select id as userId,username as userName,address as userAddress,sex as userSex from user;
</select>
【方法二】:配置方式,使用resultMap配置实体类属性名和查询结果的列名对应关系,此时需要注意的查询所有对应的配置中resultType要换为resultMap,即resultMap="userMap"。这种方式开发效率高,但是多了一步解析,所以运行效率低了些。
<!-- 查询所有-->
<resultMap id="userMap" type="com.winter.domain.User">
<!--主键字段 -->
<id property="userId" column="id"></id>
<!--非主键字段 -->
<result property="userName" column="name"></result>
<result property="userAddress" column="address"></result>
<result property="userSex" column="sex"></result>
</resultMap>
<select id="findAll" resultType="com.winter.domain.User">
select * from user;
</select>
———————————————————————————————————
本文为博主原创文章,转载请注明出处!
- 一个例子理解C#位移
- WCF后续之旅(3): WCF Service Mode Layer 的中枢—Dispatcher
- silverlight 2 Random 随机数解决方案
- 开发中巧用Enum枚举类型
- Jquery 事件冒泡
- Vue2的单元测试与调试技术
- silverlight beta 2 将在本周末发布.
- [Silverlight 4 RC]WebBrowser概览
- 英文域名chosen.com超22万元易主
- 简单介绍Docker的架构特性与局限
- .NET4.0下网站应用程序用UrlRewriter.dll重写无后缀路径 (在IIS7.5中的配置方法)
- 微信搜索新发现:iPhone 内存不足看这里!
- 建立可扩展的silverlight 应用框架 step-6
- .NET4.0下网站应用程序用UrlRewriter.dll重写无后缀路径 (在IIS7.5中的配置方法)
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- Mac OSX终端安装主题(oh my zsh)
- 谷歌浏览器油猴插件安装教程,让你的浏览器更加强大
- zabbix模块配置学习
- Windows下安装及使用NVM
- U盘上安装多个Linux发行版和PE
- ubuntu18.04部署python3、nginx项目
- CentOS8.x系统配置记录
- js根据经纬度换算行驶里程
- ubuntu18.04 安装docker
- COBBLER无人值守批量安装系统.md
- 使用VSCode 打包你的第一个flutter应用(安卓篇)
- KICKSTART无人值守批量安装系统.md
- Centos7-Firewall防火墙基础讲解
- 优酷iOS插件化页面架构方法
- 处理一次k8s、calico无法分配podIP的心路历程