四,Mybatis进行数据写入
一,Mybatis写操作包含三种:
-
插入 <insert>
-
更新 <update>
-
删除 <delete>
二,数据库事务:
客户端向mysql发起连接操作后,如果遇到写操作,并不是直接写入到某个表中,而是需要先被事务日志记录(类似流水账),然后当客户端向mysql发起commit命令的时候,事务日志才会将数据同时写入到数据表中,commit后才是真正的写入。当数据被成功写入数据表中,事务日志会被清空。如果客户端处理数据时候有些数据未执行成功,客户端会发起rollback回滚命令,当mysql收到回滚命令后,当前事务日志中所有已经产生的数据都会被清除,这些数据就不会被放入数据表中,只有当所有数据都完成,再由客户端发起提交请求,我们的数据才会被成功写入。
三,Mybatis进行数据新增
新增操作比起更新和删除操作,有一点比较复杂,新增完数据后,因为大多数情况下,id是自动生成的,新增完数据后,我们希望原始的数据对象得到新插入数据的编号,我们需要在insert语句中,增加selectkey子标签,在标签中指定select last_insert_id(),获取当前数据库连接最后产生的id号,并重新赋值给goods_id
配置文件
<?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="goods">
<insert id="insert" parameterType="com.imooc.mybatis.entity.Goods">
insert into t_goods(title,sub_title,original_cost,current_price,discount,is_free_delivery,category_id)
values (#{title},#{subTitle},#{originalCost},#{currentPrice},#{discount},#{isFreeDelivery},#{categoryId})
<!--order:执行顺序,设置成after表示在上面语句执行后操作。resultType:设置的函数的返回值类型,keyProperty:要设置的
上面语句执行完毕后,执行下面的sql语句,将得到的值回添到goodsid属性中-->
<selectKey resultType="integer" keyProperty="id" order="AFTER">
<!-- 获取当前连接最后产生的id号,并自动填充给goods里面的id主键属性-->
select last_insert_id()
</selectKey>
</insert>
</mapper>
代码
@Test
public void testSelect() {
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtils.openSession();
Goods goods = new Goods();
goods.setTitle("测试商品");
goods.setSubTitle("测试子商品");
goods.setCurrentPrice(30.2f);
goods.setDiscount(2f);
goods.setIsFreeDelivery(1);
goods.setOriginalCost(300f);
goods.setCategoryId(12);
// insert方法返回插入成功的数量
int num = sqlSession.insert("goods.insert", goods);
System.out.println(goods.getTitle());
// 提交
sqlSession.commit();
} catch (Exception e) {
// 回滚
if (sqlSession != null) {
sqlSession.rollback();
}
throw e;
} finally {
MyBatisUtils.closeSqlSession(sqlSession);
}
}
四,selectKey与useGeneratedKeys
上面我们提到插入数据的时候,如果需要获取自增主键,需要使用selectKey进行获取。我们除了可以使用这种方式,还可以使用useGeneratedKeys的方式进行主键的获取,方式如下:
<!--keyProperty:在实体类里的id名称,keyColumn:表里的id名称,useGeneratedKeys:是否自动生成主键,默认是否-->
<insert id="insert" parameterType="com.imooc.mybatis.entity.Goods" useGeneratedKeys="true"
keyProperty="id" keyColumn="goods_id">
insert into t_goods(title,sub_title,original_cost,current_price,discount,is_free_delivery,category_id)
values (#{title},#{subTitle},#{originalCost},#{currentPrice},#{discount},#{isFreeDelivery},#{categoryId})
</insert>
两者书写方式对比:
在这里插入图片描述
selectKey与useGeneratedKeys的区别:
- 显示与隐式:
selectKey标签需要明确编写获取最新主键的sql语句:(select last_insert_id()
useGeneratedKeys属性会自动根据驱动生成对应的sql语句,会随着数据库的变化自动变化 -
应用场景不同:
seleKey适用于所有的关系型数据库
useGeneratedKeys只支持自增主键类型的数据库(支持的数据库比如mysql, sqlserver,不支持的数据库为Oracle等)
总结:
selectKey标签是通用方案,适用于所有数据库,但编写麻烦(因为每种数据库获取最新主键的方式都不一致),适用于复杂的应用场景,比如大公司的项目有多种数据库对数据进行支撑和保存
useGeneratedKeys只支持自增主键类型的数据库,使用简单(绝大多数场景适用,推荐)
在这里插入图片描述
五,更新和删除操作
-
更新:
更新是对已有数据进行处理,不建议通过手动set来组织原始数据,推荐先获取原 有数据,再对原有数据进行更新操作,保证数据的影响是最小的
配置如下:
<update id="update" parameterType="com.imooc.mybatis.entity.Goods">
update t_goods set title= #{title} where goods_id= #{id};
</update>
@Test
public void testUpdate() {
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtils.openSession();
Goods goods = sqlSession.selectOne("goods.selectById", 2680);
goods.setTitle("更新商品");
int num = sqlSession.update("goods.update", goods);
sqlSession.commit();
System.out.println(goods.getTitle());
System.out.println(goods.getSubTitle());
} catch (Exception e) {
if (sqlSession != null) {
sqlSession.rollback();
}
} finally {
sqlSession.close();
}
}
-
删除:
因为大多数删除操作是根据主键来进行的,因此在xml文件配置的时候,parameterType只需要声明主键类型是int即可。
配置:
<delete id="delete" parameterType="int">
delete from t_goods where goods_id=#{id}
</delete>
@Test
public void testDelete() {
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtils.openSession();
int num = sqlSession.delete("goods.delete", 2680);
sqlSession.commit();
} catch (Exception e) {
if (sqlSession != null) {
sqlSession.rollback();
}
} finally {
sqlSession.close();
}
}