1. insert用法
1.1 簡單的insert方法
假如現在我們想新增一個用戶,該如何操作呢?
首先,在接口SysUserMapper中添加如下方法。
/**
* 新增用戶
*
* @param sysUser
* @return
*/
int insert(SysUser sysUser);
然后打開對應的SysUserMapper.xml文件,添加如下語句。
<insert id="insert">
INSERT INTO sys_user(id, user_name, user_password, user_email, user_info, head_img, create_time)
VALUES (#{id},#{userName},#{userPassword},#{userEmail},#{userInfo},#{headImg,jdbcType=BLOB},#{createTime,jdbcType=TIMESTAMP})
</insert>
特別說明:
1)為了防止類型錯誤,對於一些特殊的數據類型,建議指定具體的jdbcType值。例如headImg指定BLOB類型,createTime指定TIMESTAMP類型。
2)BLOB對應的類型是ByteArrayInputStream,就是二進制數據流。
3)由於數據庫區分date、time、datetime類型,但是在Java中一般都使用java.util.Date類型。因此為了保證數據類型的正確,需要手動指定日期類型。date、time、datetime對應的JDBC類型分別為DATE、TIME、TIMESTAMP。
在SysUserMapperTest測試類中添加如下代碼,測試下insert()方法。
@Test
public void testInsert() {
SqlSession sqlSession = getSqlSession();
try {
SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
SysUser sysUser = new SysUser();
sysUser.setUserName("test1");
sysUser.setUserPassword("123456");
sysUser.setUserEmail("test@mybatis.tk");
sysUser.setUserInfo("test info");
// 正常情況下應該讀入一張圖片保存到byte數組中
sysUser.setHeadImg(new byte[]{1, 2, 3});
sysUser.setCreateTime(new Date());
// 這里的返回值result是執行的SQL影響的行數
int result = sysUserMapper.insert(sysUser);
// 只插入1條數據
Assert.assertEquals(1, result);
// id為null,沒有給id賦值,並且沒有配置回寫id的值
Assert.assertNull(sysUser.getId());
} finally {
// 為了不影響其他測試,這里選擇回滾
// 默認的sqlSessionFactory.openSession()是不自動提交的
// 因此不手動執行commit也不會提交到數據庫
sqlSession.rollback();
sqlSession.close();
}
}
運行該測試方法,輸出日志如下。
DEBUG [main] - ==> Preparing: INSERT INTO sys_user(id, user_name, user_password, user_email, user_info, head_img, create_time) VALUES (?,?,?,?,?,?,?)
DEBUG [main] - ==> Parameters: null, test1(String), 123456(String), test@mybatis.tk(String), test info(String), java.io.ByteArrayInputStream@544a2ea6(ByteArrayInputStream), 2019-07-02 13:09:07.822(Timestamp)
DEBUG [main] - <== Updates: 1
現在我們修改下createTime指定的jdbcType類型,直觀的理解下jdbcType值的作用。
createTime,jdbcType=DATE
再次運行測試方法,日志中createTime字段的值如下。
2019-07-02(Date)
再次修改createTime指定的jdbcType類型為TIME。
createTime,jdbcType=TIME
再次運行測試方法,發現報如下錯誤:
報錯的原因是,數據庫中的字段類型為datetime,但是這里只有time部分的值。
通過上面的測試,說明數據庫的datetime類型可以存儲DATE(時間部分默認為00:00:00)和TIMESTAMP這兩種類型的時間,不能存儲TIME類型的時間。
1.2 返回主鍵值(JDBC方式)
在1.1的例子中,新增完數據,我們並沒有拿到數據庫中自增的id值,但有些場景中,我們需要先拿到數據庫中自增的值,然后再處理其余的邏輯,那么如何拿到數據庫中的自增的id值呢?
首先,在接口SysUserMapper中添加方法如下。
/**
* 新增用戶-使用useGeneratedKeys方式
*
* @param sysUser
* @return
*/
int insertUseGeneratedKeys(SysUser sysUser);
然后打開對應的SysUserMapper.xml,添加如下代碼。
<insert id="insertUseGeneratedKeys" useGeneratedKeys="true" keyProperty="id">
INSERT INTO sys_user(user_name, user_password, user_email, user_info, head_img, create_time)
VALUES (#{userName},#{userPassword},#{userEmail},#{userInfo},#{headImg,jdbcType=BLOB},#{createTime,jdbcType=TIMESTAMP})
</insert>
useGeneratedKeys設置為ture后,MyBatis會使用JDBC的getGeneratedKeys()方法來取出由數據庫內部生成的主鍵。獲取到主鍵后將其賦值給keyProperty配置的id屬性。
在SysUserMapperTest測試類中添加如下代碼,測試新增的insertUseGeneratedKeys()方法。
@Test
public void testInsertUseGeneratedKeys() {
SqlSession sqlSession = getSqlSession();
try {
SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
SysUser sysUser = new SysUser();
sysUser.setUserName("test1");
sysUser.setUserPassword("123456");
sysUser.setUserEmail("test@mybatis.tk");
sysUser.setUserInfo("test info");
// 正常情況下應該讀入一張圖片保存到byte數組中
sysUser.setHeadImg(new byte[]{1, 2, 3});
sysUser.setCreateTime(new Date());
// 這里的返回值result是執行的SQL影響的行數
int result = sysUserMapper.insertUseGeneratedKeys(sysUser);
// 只插入1條數據
Assert.assertEquals(1, result);
// 因為id回寫,所以id不為null
Assert.assertNotNull(sysUser.getId());
} finally {
sqlSession.rollback();
sqlSession.close();
}
}
運行該測試方法,測試通過,輸出日志如下。
DEBUG [main] - ==> Preparing: INSERT INTO sys_user(user_name, user_password, user_email, user_info, head_img, create_time) VALUES (?,?,?,?,?,?)
DEBUG [main] - ==> Parameters: test1(String), 123456(String), test@mybatis.tk(String), test info(String), java.io.ByteArrayInputStream@544a2ea6(ByteArrayInputStream), 2019-07-02 14:02:22.506(Timestamp)
DEBUG [main] - <== Updates: 1
1.3 返回主鍵值(selectKey方式)
1.2中回寫主鍵的方法只適用於支持主鍵自增的數據庫。
但有些數據庫(比如Oracle)不提供主鍵自增的功能,而是使用序列得到一個值,然后將這個值賦給id,再將數據插入到數據庫。
對於這種情況,就可以采用selectKey方式,因為selectKey方式不僅適用於不提供主鍵自增功能的數據庫,也適用於提供主鍵自增功能的數據庫。
我們先來看下MySql的例子。
首先,在接口SysUserMapper中添加如下方法。
/**
* 新增用戶-使用selectKey方式
*
* @param sysUser
* @return
*/
int insertUseSelectKey(SysUser sysUser);
然后打開對應的SysUserMapper.xml文件,添加如下代碼。
<insert id="insertUseSelectKey">
INSERT INTO sys_user(user_name, user_password, user_email, user_info, head_img, create_time)
VALUES (#{userName},#{userPassword},#{userEmail},#{userInfo},#{headImg,jdbcType=BLOB},#{createTime,jdbcType=TIMESTAMP})
<selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
</insert>
和1.2相比,這里的語句多了selectKey標簽,其中:
- keyColumn:主鍵的數據庫列名。
- resultType:返回值類型。
- keyProperty:主鍵對應的屬性名。
- order:該屬性的設置和使用的數據庫有關,如果使用的是MySql數據庫,設置的值是AFTER,因為當前記錄的主鍵值在insert語句執行成功后才能獲取到。如果使用的是Oracle數據庫,設置的值是BEFORE,因為Oracle中需要先從序列獲取值,然后將值作為主鍵插入到數據庫中。
如果數據庫是Oracle的話,語句如下(因為環境問題,以下代碼我並未驗證,有興趣的同學可以自己試下)。
<insert id="insertUseSelectKey">
<selectKey keyColumn="id" resultType="long" keyProperty="id" order="BEFORE">
SELECT SEQ_ID.nextval from dual
</selectKey>
INSERT INTO sys_user(id,user_name, user_password, user_email, user_info, head_img, create_time)
VALUES (#{id},#{userName},#{userPassword},#{userEmail},#{userInfo},#{headImg,jdbcType=BLOB},#{createTime,jdbcType=TIMESTAMP})
</insert>
2. update用法
假如我們現在希望通過主鍵id來更新用戶信息,該如何操作呢?
首先,在接口SysUserMapper中添加如下方法。
/**
* 根據主鍵更新
*
* @param sysUser
* @return
*/
int updateById(SysUser sysUser);
然后,打開對應的SysUserMapper.xml文件,添加如下代碼。
<update id="updateById">
UPDATE sys_user
SET user_name = #{userName},
user_password = #{userPassword},
user_email = #{userEmail},
user_info = #{userInfo},
head_img = #{headImg,jdbcType=BLOB},
create_time = #{createTime,jdbcType=TIMESTAMP}
WHERE id = #{id}
</update>
最后在SysUserMapperTest測試類中,添加如下測試方法。
@Test
public void testUpdateById() {
SqlSession sqlSession = getSqlSession();
try {
SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
SysUser sysUser = sysUserMapper.selectById(1L);
Assert.assertEquals("admin", sysUser.getUserName());
sysUser.setUserName("admin_test");
sysUser.setUserEmail("admin_test@mybatis.tk");
sysUser.setUserInfo("test info");
// 正常情況下應該讀入一張圖片保存到byte數組中
sysUser.setHeadImg(new byte[]{1, 2, 3});
sysUser.setCreateTime(new Date());
// 這里的返回值result是執行的SQL影響的行數
int result = sysUserMapper.updateById(sysUser);
// 只更新1條數據
Assert.assertEquals(1, result);
sysUser = sysUserMapper.selectById(1L);
Assert.assertEquals("admin_test", sysUser.getUserName());
Assert.assertEquals("admin_test@mybatis.tk", sysUser.getUserEmail());
} finally {
sqlSession.rollback();
sqlSession.close();
}
}
運行測試方法,測試通過,輸出的部分日志如下。
DEBUG [main] - ==> Preparing: UPDATE sys_user SET user_name = ?, user_password = ?, user_email = ?, user_info = ?, head_img = ?, create_time = ? WHERE id = ?
DEBUG [main] - ==> Parameters: admin_test(String), 123456(String), admin_test@mybatis.tk(String), test info(String), java.io.ByteArrayInputStream@78186a70(ByteArrayInputStream), 2019-07-02 14:57:34.792(Timestamp), 1(Long)
DEBUG [main] - <== Updates: 1
3. delete用法
假如我們現在希望通過主鍵id來刪除用戶信息,該如何操作呢?
首先,在接口SysUserMapper中添加如下方法。
/**
* 根據主鍵刪除
*
* @param id
* @return
*/
int deleteById(Long id);
/**
* 根據對象的主鍵刪除
*
* @param sysUser
* @return
*/
int deleteBySysUser(SysUser sysUser);
然后,打開對應的SysUserMapper.xml文件,添加如下代碼。
<delete id="deleteById">
DELETE FROM sys_user WHERE id = #{id}
</delete>
<delete id="deleteBySysUser">
DELETE FROM sys_user WHERE id = #{id}
</delete>
最后在SysUserMapperTest測試類中,添加如下測試方法。
@Test
public void testDeleteById() {
SqlSession sqlSession = getSqlSession();
try {
SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);
SysUser sysUser = sysUserMapper.selectById(1L);
Assert.assertNotNull(sysUser);
// 這里是直接根據id刪除
int result = sysUserMapper.deleteById(1L);
// 只刪除1條數據
Assert.assertEquals(1, result);
Assert.assertNull(sysUserMapper.selectById(1L));
SysUser sysUser2 = sysUserMapper.selectById(1001L);
Assert.assertNotNull(sysUser2);
// 這里是根據對象的id屬性刪除
Assert.assertEquals(1, sysUserMapper.deleteBySysUser(sysUser2));
Assert.assertNull(sysUserMapper.selectById(1001L));
} finally {
sqlSession.rollback();
sqlSession.close();
}
}
運行測試方法,測試通過,輸出的部分日志如下。
DEBUG [main] - ==> Preparing: DELETE FROM sys_user WHERE id = ?
DEBUG [main] - ==> Parameters: 1(Long)
DEBUG [main] - <== Updates: 1
4. 源碼及參考
源碼地址:https://github.com/zwwhnly/mybatis-action.git,歡迎下載。
劉增輝《MyBatis從入門到精通》
原創不易,如果覺得文章能學到東西的話,歡迎點個贊、評個論、關個注,這是我堅持寫作的最大動力。
如果有興趣,歡迎添加我的微信:zwwhnly,等你來聊技術、職場、工作等話題(PS:我是一名奮斗在上海的程序員)。