5.6. 任务 3:添加用户
第一步:创建 Mapped Statement ID
在映射文件 userinfo.xml 中添加 Mapped Statement ID,代码如下:
<!-- 定义 Mapped Statement ID,添加用户 -->
<insert id="insertUserInfo" parameterType="cn.itlaobing.mybatis.model.UserInfoModel">
<!--
将新增记录的主键值保存到 userInfo 对象中
SELECT LAST_INSERT_ID():获取新增记录的自增长主键值,只适用于自增长主键的情况
keyProperty:用于指定将查询到主键值保存到 parameterType 指定的对象的哪个属性
order:设置 SELECT LAST_INSERT_ID()相对于 insert 语句的执行顺序,其值可以是 AFTER
和 BEFORE
resultType:指定 SELECT LAST_INSERT_ID()的结果类型
-->
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
SELECT LAST_INSERT_ID()
</selectKey>
INSERT INTO userinfo(userName,userPass,birthday,gender,address)
VALUES(#{userName},#{userPass},#{birthday},#{gender},#{address});
</insert>
第二步:编写单元测试
在 TestEshop 单元测试类中添加单元测试方法,代码如下:
@Test
public void testInsertUser() {
// 通过工厂得到 SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 插入用户对象
UserInfoModel model = new UserInfoModel();
model.setUserName("宋江");
model.setUserPass("songjiang");
model.setBirthday(new Date());
model.setGender("男");
model.setAddress("山东郓城");
sqlSession.insert("eshop.insertUserInfo", model);
// 提交事务
sqlSession.commit();
// 获取用户信息主键
System.out.println(model.getId());
// 关闭会话
sqlSession.close();
}
第三步:单元测试
运行单元测试,控制台输出日志如下
15:22:11,068 DEBUG insertUserInfo:159 - ==> Preparing: INSERT INTO
userinfo(userName,userPass,birthday,gender,address) VALUES(?,?,?,?,?);
15:22:11,100 DEBUG insertUserInfo:159 - ==> Parameters: 宋江(String), songjiang(String),
2017-09-22 15:22:10.833(Timestamp), 男(String), 山东郓城(String)
15:22:11,100 DEBUG insertUserInfo:159 - <== Updates: 1
15:22:11,100 DEBUG insertUserInfo!selectKey:159 - ==> Preparing: SELECT LAST_INSERT_ID()
15:22:11,100 DEBUG insertUserInfo!selectKey:159 - ==> Parameters:
15:22:11,115 DEBUG insertUserInfo!selectKey:159 - <== Total: 1
15:22:11,115 DEBUG JdbcTransaction:70 - Committing JDBC Connection
[com.mysql.jdbc.JDBC4Connection@4493d195]
新增记录的主键值是:5
- 日志中输出了执行的 sql 语句为 INSERT INTO userinfo(userName,userPass,birthday, gender,address) VALUES(?,?,?,?,?);
- 传入参数是 Parameters:宋江(String), songjiang(String), 2017-09-22
15:22:10.833(Timestamp), 男(String), 山东郓城(String) - 输出结果是:Updates: 1
5.7. 任务 4:UUID 主键策略
使用自增长作为主键生成策略存在缺陷,记录的主键值容易被猜测,从而导致不安全,例如当要删除 id=1 的记录时,如果用户输入 2,导致 id=2,则将第二条记录被删掉。 UUID 是用于生成 36 位长度的用于不重复的字符串,将此字符串作为记录的主键可以避免自增长主键的缺陷。java.util.UUID 类的 randomUUID()方法和MySQL 中的 uuid()函数都可以生成 UUID 字符串。
<insert id="uuid" parameterType="cn.itlaobing.mybatis.model.UserInfoModel">
<!--
使用 mysql 的 uuid()作为新增记录的主键值,uuid()能够生成长度为 36 位的永远不重复
的字符串,避免了自增长主键值能被猜测的缺陷
1:通过 select uuid()得到 uuid 字符串,将 uuid 字符串设置到 userInfo 对象的 id 属性中
2:在执行 insert 时,从 userInfo 对象中取出 id 的值
-->
<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
SELECT uuid()
</selectKey>
INSERT INTO userinfo(id,userName,userPass,birthday,gender,address)
VALUES(#{id},#{userName},#{userPass},#{birthday},#{gender},#{address});
</insert>
5.8. 任务 5:更新用户
第一步:创建 Mapped Statement ID
在映射文件 userinfo.xml 中添加 Mapped Statement ID,代码如下:
<!-- 定义 Mapped Statement ID,更新用户 -->
<update id="updateUserInfo" parameterType="cn.itlaobing.mybatis.model.UserInfoModel">
update userinfo set userName=#{userName},birthday=#{birthday},gender=#{gender},
address=#{address} where id=#{id}
</update>
第二步:编写单元测试
在 TestEshop 单元测试类中添加单元测试方法,代码如下:
@Test
public void testUpdateUserInfo() {
// 通过工厂得到 SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 插入用户对象
UserInfoModel model = new UserInfoModel();
model.setId(5);
model.setUserName("宋江江");
model.setUserPass("songjiang");
model.setBirthday(new Date());
model.setGender("男");
model.setAddress("山东郓城");
sqlSession.update("eshop.updateUserInfo", model);
// 提交事务
sqlSession.commit();
// 关闭会话
sqlSession.close();
}
第三步:单元测试
运行单元测试,控制台输出日志如下
15:50:39,572 DEBUG updateUserInfo:159 - ==> Preparing: update userinfo set
userName=?,birthday=?,gender=?,address=? where id=?
15:50:39,619 DEBUG updateUserInfo:159 - ==> Parameters: 宋江江(String), 2017-09-22
15:50:39.322(Timestamp), 男(String), 山东郓城(String), 5(Integer)
15:50:39,619 DEBUG updateUserInfo:159 - <== Updates: 1
15:50:39,619 DEBUG JdbcTransaction:70 - Committing JDBC Connection
- 日志中输出了执行的 sql 语句为 update userinfo set userName=?,birthday=?,gender=?, address=? where id=?
- 传入参数是宋江江(String), 2017-09-22 15:50:39.322(Timestamp), 男(String), 山东郓城(String), 5(Integer)
- 输出结果是:Updates: 1
- 查看数据库,宋江的名字更改为宋江江
- 注意:在更新数据时,被更新的 POJO 对象中必须存在主键值
5.9. 任务 6:删除用户
第一步:创建 Mapped Statement ID
在映射文件 userinfo.xml 中添加 Mapped Statement ID,代码如下:
<!-- 定义 Mapped Statement ID,删除用户 -->
<delete id="deleteUserInfo" parameterType="java.lang.Integer">
delete from userinfo where id=#{id}
</delete>
第二步:编写单元测试
在 TestEshop 单元测试类中添加单元测试方法,代码如下:
@Test
public void testDeleteUserInfo() {
// 通过工厂得到 SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//传入被删除记录的主键值 5
sqlSession.delete("eshop.deleteUserInfo", 5);
// 提交事务
sqlSession.commit();
// 关闭会话
sqlSession.close();
}
第三步:单元测试
运行单元测试,控制台输出日志如下
15:59:12,021 DEBUG deleteUserInfo:159 - ==> Preparing: delete from userinfo where id=?
15:59:12,059 DEBUG deleteUserInfo:159 - ==> Parameters: 5(Integer)
15:59:12,069 DEBUG deleteUserInfo:159 - <== Updates: 1
15:59:12,070 DEBUG JdbcTransaction:70 - Committing JDBC Connection
- 日志中输出了执行的 sql 语句为 delete from userinfo where id=?
- 传入参数是 5(Integer)
- 输出结果是:Updates: 1
- 查看数据库,id=5 的用户被删除
5.10. MyBatis 解决了 JDBC 编程的问题
通过以上对用户的添加、删除、修改、查询的例子,发现 MyBatis 框架让程序开发人员将精力集中在 SQL 本身,而不必将精力放在例如加载驱动、创建 connection、创建 statement、设置参数、结果集检索等 jdbc 繁杂的过程里。解决了 JDBC 编程的问题,具体过程如下:
- 数据库连接对象的创建、释放频繁,造成系统资源浪费从而影响系统性能,如果使用数据库连接池可解决此问题。在 SqlMapConfig.xml 中配置数据连接池,使用连接池管理数据库连接。
- Sql 语句写在代码中造成代码不易维护,实际应用 sql 变化的可能较大,sql 变动需要改变 java 代码。MyBatis 框架将 Sql 语句配置在映射文件中(mapper.xml)与java 代码分离。
- 传入参数繁琐,SQL 语句的 where 条件中占位符的个数可能会变化,Mybatis 自动将 java对象映射至 sql 语句,通过 statement 中的 parameterType 定义输入参数的类型。
- 对结果集解析繁琐,sql 变化导致解析代码变化,且解析前需要遍历,Mybatis 自动将 sql执行结果映射至 POJO 对象,通过 statement 中的 resultType 定义输出结果的类型。