主键生成
Oracle 支持 IDENTITY 列,也长期使用 sequence 生成主键。两种方式在 dbVisitor 中的推荐配置不同:
IDENTITY:插入后由数据库生成,使用 JDBC generated keys 回填。- sequence:插入前先取序列值,再把主键值带入 INSERT。
说明
通用配置见主键生成与回填。
主键策略
| 策略 | 本数据源的用法 |
|---|---|
| 手工赋值 | 插入前由应用提供主键。 |
| 自增 | 由数据库生成数值主键。 |
| UUID | 字符主键使用 UUID32 或 UUID36。 |
| 序列 | 插入前取得序列值。 |
| 自定义 | 使用自定义生成器,在插入前或后处理主键。 |
使用 IDENTITY
Oracle 12c+ 可以使用 IDENTITY 列:
CREATE TABLE user_info (
id NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name VARCHAR2(64),
age NUMBER
)
- 构造器 API
- 方法注解
- Mapper 文件
主键属性配置 KeyType.Auto,插入后自动回填。
Oracle IDENTITY 映射
@Table("user_info")
public class UserInfo {
@Column(value = "id", primary = true, keyType = KeyType.Auto)
private Integer id;
@Column("name")
private String name;
@Column("age")
private Integer age;
}
新增后属性自动回填
UserInfo user = new UserInfo();
user.setName("mali");
user.setAge(18);
LambdaTemplate lambda = ...;
int rows = lambda.insert(UserInfo.class)
.applyEntity(user)
.executeSumResult();
Integer id = user.getId();
注意
- 多个对象逐条插入、分别回填主键,不使用 JDBC 批处理。
- 发生插入冲突时,跳过插入或更新已有记录不保证回填主键。
设 置 useGeneratedKeys = true,用 keyProperty 指定回填属性、keyColumn 指定主键列:
@Insert(
value = "INSERT INTO user_info (name, age) VALUES (#{name}, #{age})",
useGeneratedKeys = true,
keyProperty = "id",
keyColumn = "id"
)
int insertUser(UserInfo user);
设置 useGeneratedKeys="true",用 keyProperty 指定回填属性、keyColumn 指定主键列:
Oracle IDENTITY generated keys
<insert id="insertUser"
useGeneratedKeys="true"
keyProperty="id"
keyColumn="id">
INSERT INTO user_info (name, age)
VALUES (#{name}, #{age})
</insert>
使用序列
下面使用普通主键列和序列,与上面的 IDENTITY 示例独立:
CREATE TABLE user_info (
id NUMBER(10) PRIMARY KEY,
name VARCHAR2(100),
age NUMBER(3)
);
CREATE SEQUENCE user_info_seq START WITH 1 INCREMENT BY 1;
- 构造器 API
- 方法注解
- Mapper 文件
主键属性配置 KeyType.Sequence,通过 @KeySeq 指定序列:
import net.hasor.dbvisitor.mapping.Column;
import net.hasor.dbvisitor.mapping.KeySeq;
import net.hasor.dbvisitor.mapping.KeyType;
import net.hasor.dbvisitor.mapping.Table;
@Table("user_info")
public class UserInfo {
@Column(primary = true, keyType = KeyType.Sequence)
@KeySeq("user_info_seq")
private Integer id;
private String name;
private Integer age;
// 省略 getter 和 setter
}
UserInfo user = new UserInfo();
user.setName("mali");
lambda.insert(UserInfo.class)
.applyEntity(user)
.executeSumResult();
插入前自动执行 SELECT user_info_seq.NEXTVAL FROM dual,将值写入 user.id,再插入记录。传入多个实体时,每个实体分别获取序列值。
注解方式可以使用 @SelectKeySql:
@SelectKeySql(
value = "SELECT user_info_seq.NEXTVAL AS id FROM dual",
keyProperty = "id",
keyColumn = "id",
order = Order.Before
)
@Insert("INSERT INTO user_info (id, name, age) VALUES (#{id}, #{name}, #{age})")
int insertUser(UserInfo user);
Mapper 文件使用 selectKey
<insert id="insertUser">
<selectKey keyProperty="id" keyColumn="id" order="BEFORE">
SELECT user_info_seq.NEXTVAL AS id FROM dual
</selectKey>
INSERT INTO user_info (id, name, age)
VALUES (#{id}, #{name}, #{age})
</insert>
选择回填来源
方法注解和 Mapper 文件均使用 useGeneratedKeys,保持默认回填来源。生成键和命令本身的结果集不是同一个结果;这里的插入不要设置 generatedKeySource="resultSet"。
RETURNING ... INTO 返回的字段使用 OUT 参数接收,见数据回填。