Mybatis中的@SelectKey注解
一、创建Maven项目
在pom.xml中,添加mybatis依赖,mysql-jdbc依赖,把编译版本改为1.8
你问,为啥mybatis不会自动依赖mysql-jdbc,需要手动写明?答:因为mysql驱动是通过字符串动态加载的,这是一种“动态依赖”,Maven只能推导出“静态依赖”。“动态依赖”是一种更加灵活的依赖。
Maven默认的Java版本是1.6,无法使用lambda表达式(1.8)和钻石运算符(1.7)。
代码片段:pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>wyf</groupId><artifactId>xqweb</artifactId><version>1.0-SNAPSHOT</version><dependencies><!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.4</version></dependency><!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --><!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>6.0.6</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><target>1.8</target><encoding>utf8</encoding></configuration></plugin></plugins></build></project>
创建好了pom.xml,就可以开始编码了。最终的目录结构如下,下面让我们来一步一步创建文件。
二、配置Mybatis
代码片段:mybatis.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><properties resource="config.properties"></properties><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment></environments><mappers><mapper class="haha.UserDao"/><mapper resource="user.xml"/></mappers>
</configuration>
代码片段:config.properties
username=root
password=haha
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai
把配置信息跟mybatis.xml分开的好处是:更清晰。mybatis属于代码区,config.properties改起来比较简单。
三、创建实体类User
User有三个属性:name,age和id,重写toString()方法便于调试。
package haha;
public class User {
String name;
Integer age;
Integer id;
public User(){}
public User(String name,int age){this.name=name;this.age=age;
}
public String getName() {return name;
}public void setName(String name) {this.name = name;
}public Integer getAge() {return age;
}public void setAge(Integer age) {this.age = age;
}public Integer getId() {return id;
}public void setId(Integer id) {this.id = id;
}@Override
public String toString() {return String.format("(id:%d,name:%s,age:%d)", id, name, age);
}
}
相应的,在数据库中建立一个表user
CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(10) DEFAULT NULL,`age` int(11) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=119 DEFAULT CHARSET=utf8mb4
四、实现UserDao接口
UserDao接口有两个功能:插入、查询全部。
package haha;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.SelectKey;import java.util.List;public interface UserDao {
@Insert("insert into user(name,age) value(#{name},#{age})")
int insert_withoutPrimaryKey(@Param("name") String name, @Param("age") int age);int insert_useGeneratedKey(@Param("user") User user);int insert_selectKey(@Param("user") User user);@Insert("insert into user(name,age) value(#{user.name},#{user.age})")
@SelectKey(statement = "select last_insert_id()", keyProperty = "user.id", before = false, resultType = int.class)
int insert_selectKeyAnotation(@Param("user") User user);@Select("select*from user")
List<User> getAll();
}
Mybatis写SQL语句有两种方式:1、使用注解;2、使用xml
对于比较长的SQL语句放在xml中,对于比较短的SQL语句放在注解中
在上面定义的UserDao中,insert_userGeneratedKey()和insert_selectKey()两个函数没有给出对应的SQL语句,需要在xml文件中进行定义。
代码片段:user.xml
<?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="haha.UserDao"><insert id="insert_useGeneratedKey" parameterType="haha.User"useGeneratedKeys="true" keyProperty="user.id">insert into user set id=#{user.id},name=#{user.name},age=#{user.age}</insert><insert id="insert_selectKey" parameterType="haha.User"><selectKey keyProperty="user.id" keyColumn="id" order="AFTER" resultType="int">SELECT last_insert_id()</selectKey>insert into user(name,age) VALUE (#{user.name},#{user.age})</insert>
</mapper>
五、万事俱备,只欠东风
编写一个UserService类测试一下
package haha;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;
import java.io.InputStream;
import java.util.List;public class UserService {public static void main(String[] args) throws IOException {String resource = "mybatis.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();SqlSessionFactory factory = builder.build(inputStream);SqlSession session = factory.openSession();UserDao dao = session.getMapper(UserDao.class);//使用默认主键int affectedRows = dao.insert_withoutPrimaryKey("张三", 25);System.out.println(affectedRows);//使用useGeneratedKey,将主键注入到user.id中User u = new User("张三", 17);affectedRows = dao.insert_useGeneratedKey(u);System.out.println(affectedRows + " " + u.getId());//使用selectKey执行在插入之前或之后执行查询语句affectedRows = dao.insert_selectKey(u);System.out.println(affectedRows + " " + u.getId());//使用selectKey注解的方式affectedRows = dao.insert_selectKeyAnotation(u);System.out.println(affectedRows + " " + u.getId());session.commit();List<User> a = dao.getAll();a.forEach(System.out::println);
}
}
六、insert()函数返回值
如下代码,insert()函数的返回值为int类型,表示affectedRows,即受影响的行数,如果成功插入返回1,如果不成功插入,返回0。对于一切写操作(insert,update,delete),返回值都是affectedRows。
@Insert("insert into user(name,age) value(#{name},#{age})")
int insert(@Param("name") String name, @Param("age") int age);
七、关于@SelectKey
关于insert()有一种需求很常见:如何确定插入数据的主键。对于MySQL中的自增类型主键,无需提供主键可以直接插入。还是以insert()函数为例,这个SQL语句没有提供主键,主键是自增类型可以自动生成。
@Insert("insert into user(name,age) value(#{name},#{age})")
int insert(@Param("name") String name, @Param("age") int age);
下面介绍一个重要注解@SelctKey(statement="SQL语句",keyProperty="将SQL语句查询结果存放到keyProperty中去",before="true表示先查询再插入,false反之",resultType=int.class)
其中:
- statement是要运行的SQL语句,它的返回值通过resultType来指定
- before表示查询语句statement运行的时机
- keyProperty表示查询结果赋值给代码中的哪个对象,keyColumn表示将查询结果赋值给数据库表中哪一列
- keyProperty和keyColumn都不是必需的,有没有都可以
- before=true,插入之前进行查询,可以将查询结果赋给keyProperty和keyColumn,赋给keyColumn相当于更改数据库
- befaore=false,先插入,再查询,这时只能将结果赋给keyProperty
- 赋值给keyProperty用来“读”数据库,赋值给keyColumn用来写数据库
- selectKey的两大作用:1、生成主键;2、获取刚刚插入数据的主键。
- 使用selectKey,并且使用MySQL的last_insert_id()函数时,before必为false,也就是说必须先插入然后执行last_insert_id()才能获得刚刚插入数据的ID。
注意:
- 该注解相当于XML配置中的
<selectKey>
的标签 - 与注解
@Insert
,@InsertProvider
,@Update
or@UpdateProvider
搭配使用。在其他方法上将被忽略。 - 如果你指定了一个
@SelectKey
注解,然后Mybatis将忽略任何生成的key属性通过设置@Options
,或者配置属性。 - 属性: statement是要执行的sql语句的字符串数组, keyProperty是需要更新为新值的参数对象属性, before可以是true或者false分别代表sql语句应该在执行insert之前或者之后, resultType是keyProperty的Java类型, statementType是语句的类型,取Statement, PreparedStatement和CallableStatement对应的STATEMENT, PREPARED或者CALLABLE其中一个,默认是PREPARED。
1、举一个before=true的例子,新插入数据的id是当前表中行的个数
当before=true,可以通过SQL语句来填充insert语句中的某个参数,这个参数的名称可以通过keyProperty来指明。
@Insert("insert into user value(#{id},#{name},#{age})")
@SelectKey(statement="select count(1)from user", keyProperty="id", before=true, resultType=int.class)
int insert(@Param("name") String name, @Param("age") int age);
这个函数返回值是affectedRows,也就是插入成功返回1,插入失败返回0。
以上这段代码有一个大大的隐患,万万不能用在生产环境中。这个隐患就是:不能通过count()来确定id,多线程情况下有可能产生冲突。解决方案:可以使用UUID作为主键。
2、before=false的情况
注意keyProperty不能使基本类型,因为那样赋值之后就找不到了(相当于传值)
注解的方式
@Insert("insert into user(name,age) value(#{user.name},#{user.age})")
@SelectKey(statement = "select last_insert_id()", keyProperty = "user.id", before = false, resultType = int.class)
int insert_selectKeyAnotation(@Param("user") User user);
XML的方式
<insert id="insert_selectKey" parameterType="haha.User"><selectKey keyProperty="user.id" keyColumn="id" order="AFTER" resultType="int">SELECT last_insert_id()</selectKey>insert into user(name,age) VALUE (#{user.name},#{user.age})</insert>
3、在Oracle中使用SelectKey生成主键,通常是“先查询得到主键,再进行插入”
DUAL表是Oracle中的神奇的表
使用序列作为主键
<insert id="insertSelective" parameterType="com.zehin.vpaas.base.domain.SfyHazardAnalysis">
<selectKey resultType="java.lang.Integer" order="BEFORE" keyProperty="hazardId"> SELECT SEQUENCE_1.NEXTVAL FROM DUAL
</selectKey>
insert into SFY_HAZARD_ANALYSIS
<trim prefix="(" suffix=")" suffixOverrides=","> HAZARD_ID, <if test="hazardTime != null"> HAZARD_TIME,</if> <if test="hazardTitle != null"> HAZARD_TITLE, </if> <if test="hazardMeasure != null"> HAZARD_MEASURE, </if> <if test="buildId != null"> BUILD_ID, </if>
</trim>
<trim prefix=" values(" suffix=")" suffixOverrides=","> #{hazardId,jdbcType=INTEGER}, <if test="hazardTime != null">#{hazardTime,jdbcType=VARCHAR},</if> <if test="hazardTitle != null"> #{hazardTitle,jdbcType=VARCHAR}, </if> <if test="hazardMeasure != null"> #{hazardMeasure,jdbcType=VARCHAR}, </if> <if test="buildId != null"> #{buildId,jdbcType= INTEGER}, </if>
</trim>
lt;/insert>
使用GUID作为主键
<insert id="insertUser" parameterType="com.danny.mybatis.po.User">
<selectKey keyProperty="userId" order="BEFORE" resultType="java.lang.Integer">
select SYS_GUID() as userId from DUAL</selectKey>
insert into T_USER(userId,userName,birthday,sex,address) values (#{userId},#{userName},#{birthday},#{sex},#{address}) </insert>
4、使用useGeneratedKeys
<insert id="insert" parameterType="Spares" useGeneratedKeys="true" keyProperty="id"> insert into spares(spares_id,spares_name, spares_type_id,spares_spec) values(#{id},#{name},#{typeId},#{spec}) </insert>
<insert id="insertUser" useGeneratedKeys="true" keyColumn="id">insert into user(name,age) VALUE (#{name},#{age})</insert>
八、获取刚刚插入数据的主键
除了使用selectKey的方式获取刚刚插入数据的主键,还有以下方案:
1、如果是MySQL,可以用select last_insert_id()
语句获取新插入数据的主键。
2、如果主键类型是UUID,可以直接在代码中生成主键进行插入,这样就不需要从数据库中读取主键了,主动权掌握在代码手中。
九、参考资料
Mybatis官方文档
CSDN偶尔记一下:mybatis如何获取oracle新插入数据记录的主键?
转载于:https://www.cnblogs.com/weiyinfu/p/6835301.html
Mybatis中的@SelectKey注解相关推荐
- MyBatis中的selectKey
2019独角兽企业重金招聘Python工程师标准>>> SelectKey在Mybatis中是为了解决Insert数据时不支持主键自动生成的问题,他可以很随意的设置生成主键的方式. ...
- MyBatis中的常用注解
在MyBatis中,一些SQL语句例如(select * from 表名;delete from 表名)等等,这些SQL语句比较简单,没有那些复杂的关联关系,但是在不用注解的情况下,要执行这些方法的话 ...
- Mybatis详解—@SelectKey注解
SelectKey 元素的属性 SelectKey在Mybatis中是为了解决Insert数据时不支持主键自动生成的问题. 数据库主键包括自增和非自增,有时候新增一条数据不仅仅知道成功就行了,后边的逻 ...
- MyBatis中的@Mapper注解及配套注解使用详解
https://blog.csdn.net/phenomenonstell/article/details/79033144 从mybatis3.4.0开始加入了@Mapper注解,目的就是为了不再写 ...
- Mybatis中的@Param注解
前言 今天在使用Mybatis时遇到一个问题,主要出错原因在于Mybatis的@Param注解,如果我不在参数前面加上@Param注解,数据库操作就会报错,如下: @Param作用 @Param注解的 ...
- mybatis中@Results,@ResultMap注解使用
一.Results的用法 用法一: 当数据库字段名与实体类对应的属性名不一致时,可以使用@Results映射来将其对应起来.column为数据库字段名,porperty为实体类属性名,jdbcType ...
- MyBatis中的@Mapper注解使用
前言:从mybatis3.4.0开始加入了@Mapper注解,目的就是为了不再写mapper映射文件. Mapper作用 作用:在接口类上添加了@Mapper,在编译之后会生成相应的接口实现类 添加位 ...
- mybatis 中标签selectkey的作用
<selectKey>标签的作用 https://blog.csdn.net/xueguchen/article/details/108703837
- mybatis中传入String类型参数的问题
1. 出现的问题 需求是想写一个按公司名字查询公司列表的功能,最开始的代码如下 Dao层接口如下: @MyBatisDao public interface OfficeDao extends Tre ...
最新文章
- SQL Server 学习系列之五
- php不使用递归实现无限极分类
- dmidecode 命令详解(获取硬件信息)
- 攻防世界php2_攻防世界-php2
- 包装类java_java中的包装类
- Python基本图形绘制之“蟒蛇绘制”
- 随便选一张扑克牌_扑克牌魔术手法教学,简单易学的纸牌魔术,三分钟让你成为大师...
- c语言常用算法分析 微盘,C语言常用算法归纳.pdf
- C语言之字符串探究(一):字符串与字符数组
- left join 一对多只取一条_Python爬虫教程:验证码的爬取和识别详解
- Audio / Video Playback
- linux 自学系列:文件压缩
- c语言二级考试程序设计题难吗,计算机二级c语言难吗 考试题型是什么
- 业务如何驱动技术发展
- 如何驱动直流电机H桥驱动笔记
- 数学建模·层次分析法基本步骤及参考代码
- Python:peewee常用操作CRUD
- mysql单节点扩展为主从复制_MySQL主从复制
- 学通信工程兼修计算机,创名堂 | 第二期创名堂ARES战队
- 图麟信息科技联合创始人张勋:全面商用化到来,AI全方面融入行业
热门文章
- scrapy.Request使用meta传递数据,以及deepcopy的使用
- Android仿苹果版QQ下拉刷新实现(二) ——贝塞尔曲线开发鼻涕下拉粘连效果
- iOS小白之路...iOS中基础控件的使用
- oracle添加联合主键
- 从Java角度学JavaScript
- [转]web实时视频流从0到1(ffmpeg+nginx-http-flv-module+flv.js)
- [转]Hexo博客添加自定义HTML页面
- 报表如何同步用户数据集 1
- AS3.0常用第三方类库:TweenMax
- 数据分析学习笔记——Pandas库思维导图