做为一个快乐的小码农,在每个阶段每每都在重复写着不一样版本的,学生管理,用户管理,注册登陆,从 JavaSE 的控制台版,或者 GUI 版,再到 JavaWeb的 JSP版,再到纯粹使用 HTML 做为前端展现的版本,以及使用一个更新的技术,在此其中,咱们用过 txt 作数据库,用 XML 也能够,到如今经常使用的 MySQL,增删改查一直是咱们必不可少的一部份内容,即便你不懂原理,即便你对这个技术的理解不是很深入,拿出你的增删改查,噼里啪啦就是一段乱敲,好歹仍是能让你着手先作起来(固然,对技术的理解仍是很重要的),今天就和你们聊一聊 MyBatis 这门技术的 CURD (增删改查)前端
在测试方法中,读取配置文件,生产 SqlSession,释放资源等等,在每一测试方法的时候,都是重复的,因此咱们彻底能够提出出这一部分,防止大量的重复代码java
@Before public void init() throws Exception{ //读取配置文件 inputStream = Resources.getResourceAsStream("SqlMapConfig.xml"); //建立SqlSessionFactory工厂 SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream); //使用工厂生产SqlSession对象 sqlSession= factory.openSession(); //使用SqlSession建立Mapper接口的代理对象 userMapper = sqlSession.getMapper(UserMapper.class); }
@After public void destroy() throws Exception{ sqlSession.close(); inputStream.close(); }
在这两个方法上增长 @Before 和 @Aftrer 注解,就能够保证,init() 和 destory() 这两个方法,分别在咱们真正被测试的方法的先后执行sql
首先,在 UserMapper 接口中 增长对应的方法数据库
public interface UserMapper { /** * 增长用户 * @param user */ void addUser(User user); }
接着,在SQL映射文件中,增长新增的映射配置,这些有关内容放在 <insert></insert>
标签对中,具体代码以下微信
<insert id="addUser" parameterType="cn.ideal.domain.User"> insert into user(username,telephone,birthday,gender,address)values(#{username},# {telephone},#{birthday},#{gender},#{address}) </insert>
一、id 属性,天然是对应的方法名,而因为这里,咱们并不须要拿到返回信息,因此这里并无返回参数 resultType,而方法中的参数又为一个 JavaBean 类,也就是User实体类,因此须要在标签属性中,添加一个 parameterType 属性,其中须要指定这个实体类app
二、在文本中书写插入的SQL语句,因为实体类中已经快捷生成了对应的 get set 方法,所一可使用 #{}
的方式表明对应的值dom
三、提示,数据库中id为自增,因此并不须要设置 idide
因为添加是更新类的语句,因此在执行插入语句后,须要提交事务,也就是执行对应的 commit方法,以提交更新操做,若没有这一句,即便不会报错,也没法正常存入,会被回滚,且这个id被占用测试
/** * 测试新增用户 * @throws Exception */ @Test public void testUpdateUser() throws Exception{ User user = new User(); user.setId(17); user.setUsername("修改"); user.setTelephone("18899999999"); user.setBirthday(new Date()); user.setGender("女"); user.setAddress("广州"); //执行方法 userMapper.updateUser(user); }
控制台:优化
首先对于 MySQL自增主键来讲,在执行 insert语句以前,MySQL 会自动生成一个自增主键,insert执行后,经过 SELECT LAST_INSERT_ID()
能够获取这条刚插入记录的自增主键
在 SQL 映射配置文件中,须要借助 <selectKey></selectKey>
标签,有一个属性比较特殊,order 属性,它表明着相对于插入操做的执行时间,before-以前,after-以后
注:该标签插入到 <select></select>
中
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer"> SELECT LAST_INSERT_ID(); </selectKey>
测试一下
@Test public void testAddUser() throws Exception{ User user = new User(); user.setUsername("增长"); user.setTelephone("12266660000"); user.setBirthday(new Date()); user.setGender("男"); user.setAddress("珠海"); System.out.println("执行插入前" + user); //执行方法 userMapper.addUser(user); System.out.println("执行插入后" + user); }
执行效果
在 UserMapper 接口中增长修改方法
public interface UserMapper { /** * 更新用户 * @param user */ void updateUser(User user); }
在 SQL 映射文件中增长语句,内容包括在 <update></update>
中,须要注意的基本与添加操做是一致的
<update id="updateUser" parameterType="cn.ideal.domain.User"> update user set username=#{username},telephone=#{telephone},birthday=#{birthday},gender=#{gender},address=#{address} where id=#{id} </update>
/** * 测试新增用户 * @throws Exception */ @Test public void testAddUser() throws Exception{ User user = new User(); user.setUsername("增长"); user.setTelephone("12266668888"); user.setBirthday(new Date()); user.setGender("女"); user.setAddress("成都"); //执行方法 userMapper.addUser(user); }
接口中增长删除方法
public interface UserMapper { /** * 删除用户 * @param uid */ void deleteUser(Integer uid); }
在SQL映射文件中,使用 <delete></delete>
标签对进行内容的书写,须要注意的是,因为咱们传入的参数是一个 Integer类型的用户id,因此参数类型的值为 parameterType
<delete id="deleteUser" parameterType="java.lang.Integer"> delete from user where id=#{id} </delete>
/** * 测试删除用户 * @throws Exception */ @Test public void testDeleteUser() throws Exception{ //执行方法 userMapper.deleteUser(17); }
因为查询所有很是简单,这里就不展现了,基本流程都是同样的
在 UserMapper 接口中编写方法
public interface UserMapper { /** * 经过姓名模糊查询 * @param username * @return */ List<User> findByName(String username); }
在 SQL 映射文件中新增查询语句
<select id="findByName" parameterType="java.lang.String" resultType="cn.ideal.domain.User"> select * from user where username like #{username} </select>
/** * 测试模糊查询 * @throws Exception */ @Test public void testFindByName() throws Exception{ List<User> users = userMapper.findByName("%张%"); for (User user : users){ System.out.println(user); } }
在使用模糊查询的时候,咱们须要在查询条件的两侧拼接两个 “%” 字符串,这个时候有两种解决方案,一种就是像在我上述代码中,在测试时将字符串补充完整,还有一种方式就是 使用 ${}
,它在 SQL配置文件中表明一个 “拼接符号” ,也就是说能够这样写 SQL语句
select * from user where username like '%{value}'
可接受的类型有,普通类型(此状况下{}内部只能写value),JavaBean,HashMap
可是使用 %{}
拼接字符串的时候,会引发 SQL注入,因此不是很推荐使用
Mapper 的输入映射样例中,咱们对于基本数据类型和基本数据包装类,都有了必定的了解,而下面咱们来聊一聊关于相对复杂的一种状况,那就是自定义包装类
先讲一个需求:仍是关于用户的查询,可是查询条件复杂了一些,不只仅局限于用户的信息,并且可能还包括订单,购物车,或者与用户一些行为相关的信息,那么如何实现这样一种需求呢?
那咱们想,可不能够,在 User 类中增长一些咱们须要的信息
package cn.ideal.domain; public class QueryUserVo { private UserInstance userInstance; public UserInstance getUserInstance() { return userInstance; } public void setUserInstance(UserInstance userInstance) { this.userInstance = userInstance; } //其余查询条件,例如订单,购物车等等 }
咱们这里使用用户的性别以及对姓名的模糊查询,来写SQL 固然,你也能够本身经过别的信息写SQL
<select id="findUserByVo" parameterType="cn.ideal.domain.QueryUserVo" resultType="cn.ideal.domain.UserInstance"> select * from user where user.gender=#{userInstance.gender} and user.username like #{userInstance.username} </select>
在QueryUserVo 中,封装的是查询信息的各类对象,为何上述代码能够直接经过 userInstance.gender 直接取出对应的属性,这种方式叫作 OGNL 表达式,在类中 咱们的写法一般是 user.getUsername
但在写法上,OGNL 表达式将get给省略了
/** * 包装对象做为查询参数 * @throws Exception */ @Test public void testFindUserByVo() throws Exception{ //建立包装对象,设置查询条件 QueryUserVo queryUserVo = new QueryUserVo(); UserInstance userInstance = new UserInstance(); userInstance.setGender("女"); userInstance.setUsername("%张%"); queryUserVo.setUserInstance(userInstance); //调用 UserMapper 的方法 List<UserInstance> userInstances = userMapper.findUserByVo(queryUserVo); for (UserInstance u : userInstances){ System.out.println(u); } }
若是文章中有什么不足,欢迎你们留言指正,感谢你们的支持!
若是能帮到你的话,那就来关注我吧!若是您更喜欢微信文章的阅读方式,能够关注个人公众号
在这里的咱们素不相识,却都在为了本身的梦而努力 ❤一个坚持推送原创开发技术文章的公众号:理想二旬不止