返回数据库自动更新主键
1.关联数据插入操作
开发中,某些业务需要在主表/从表关联关系下,插入数据时需要保证数据完整性。关联数据插入时的流程:
2.通过序列产生主键(Oracle)
数据库表的主键一般情况下与业务无关,而且通常采用自动生成的方式。Oracle数据库采用sequence的方式产生主键,在SQL语句中,指定由哪个序列为表产生主键;而其他的一些数据库(如SQLServer、MySQL)具有自动增长主键功能。
如果仅仅是单表操作,不需要返回刚刚插入的主键值,但如果有关联关系的表操作,需要获得刚刚插入的主键值。
JDBC返回自动主键API
PreparedStatement对象在执行insert操作后会保存数据库产生的自动主键,可调用PreparedStatement的getGeneratedKeys方法获得。getGeneratedKeys的返回值为结果集对象,可以通过结果集获取刚刚生成的主键。
案例:插入class及其关联的student_2信息
class表结构如下
其中,class表的主键为cid,student_2表的主键为id。student_2表的cid列为外键,该列的数据引用class表的主键列cid的数据。
要求向class表插入数据的同时,向student_2表插入数据。student_2表的cid列的数据为之前插入class表的主键列cid的数据。另外,class表的主键列cid的数据通过序列class_seq获得,student_2表的主键列id的数据通过序列student_2_seq获得。内容如下
方案:
本案例中,向class表插入数据的同时,向student_2表插入数据。student_2表的cid列的数据为之前插入class表的主键列cid的数据。首先,将两次插入操作放在同一个事务中。另外,要获取使用序列class_seq自动生成主键列cid的数据,为向student_2表中插入数据时cid列的数据。
使用PreparedStatement获取插入操作时数据库自动生成的主键列数据的核心代码如下:
sql = “insert into class (classno, className) values(class_seq.nextval,?)”;
conn = DbUtil_Pool.getConnection();
//第一个参数表示要执行的SQL语句,第二参数表示SQL语句操作的表的主键列的列名字,并且SQL语句操作的//表包含应该返回的自动生成键。如果 SQL 语句不是 insert 语句,则驱动程序将忽略该数组
stmt = conn.prepareStatement(sql, new String[] { “cid” });
stmt.setString(1, class.getClassName());
// 执行SQL语句
stmt.executeUpdate();
rs = stmt.getGeneratedKeys();
int cid= 0;
if (rs.next()) {
cid= rs.getInt(1);
}
System.out.print(“id:” + cid);
步骤
实现此案例需要按照如下步骤进行。
步骤一:在oracle数据库中创建claxx表、students表,sql语句如下
create table claxx(
cid number primary key,
className varchar2(20) not null
);
create table students(
id number primary key,
name varchar2(30),
birthday date,
cid number,
foreign key(cid) references class(cid)
);
步骤二:
在数据库中创建序列class_seq和student_2_seq
create sequence seq_claxx_indexstart with 1 increment by 1;
create sequence seq_students_index with 1 increment by 1
步骤三:
创建Classes类和Student类,Classes类为实体类和数据表class之间的映射,Student类为实体类和数据表student_2之间的映射.
步骤四:
准备JDBC操作数据库的基本代码
首先,新建类Join,在该类中新建addStu方法;然后,准备数据库连接Connection对象、操作SQL语句的PreparedStatement对象以及设置事务管理;最后进行异常的处理.
步骤五:向class表中插入数据并获取自动生成的主键
向class表中插入数据,并使用PreparedStatement的getGeneratedKeys方法获得刚刚生成的主键.
步骤六:向student_2表中插入数据
将上一步骤中获取到的class表的主键列数据,作为student_2表的外键列cid的数据。
步骤七:
新建测试类TestJoin,新建测试方法testAdd,并构造条件中的参数Classes和Student对象。
数据库表设计
数据库表设计:
完整代码如下:
实体类:Claxx 和 Student
Claxx实体
package cn.lyc.entity;
/**
- 对应数据库的claxx表
- @author JLB
*/
public class Claxx {
private int cid;
private String cname;
public int getCid() {
return cid;
}
public void setCid(int cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
@Override
public String toString() {
return "Claxx [cid=" + cid + ", cname=" + cname + "]";
}
}
student实体
package cn.lyc.entity;
/**
- 对应数据库的students表
- @author JLB
*/
public class Student {
private int sid;
private String sname;
private int cid;
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public int getCid() {
return cid;
}
public void setCid(int cid) {
this.cid = cid;
}
@Override
public String toString() {
return "Student [sid=" + sid + ", sname=" + sname + ", cid=" + cid + "]";
}
}
连接工具类
package cn.lyc.util;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import org.apache.commons.dbcp2.BasicDataSource;
/**
- 连接池
- @author JLB
*/
public class DBUtils {
private static String DRIVER;
private static String URL;
private static String USER;
private static String PASSWORD;
private static Properties props = new Properties();
private static BasicDataSource dataSource = new BasicDataSource();
private static int initSize;
private static int minIdle;
private static int maxIdle;
private static int maxTotal;
private static long maxWait;
static {
InputStream is = DBUtils.class.getClassLoader().getResourceAsStream("db.properties");
try {
props.load(is);
DRIVER = props.getProperty("driver");
URL = props.getProperty("url");
USER = props.getProperty("user");
PASSWORD = props.getProperty("password");
initSize = Integer.valueOf(props.getProperty("initSize"));
minIdle = Integer.valueOf(props.getProperty("minIdle"));
maxIdle = Integer.valueOf(props.getProperty("maxIdle"));
maxTotal = Integer.valueOf(props.getProperty("maxTotal"));
maxWait = Long.valueOf(props.getProperty("maxWait"));
dataSource.setDriverClassName(DRIVER);
dataSource.setUrl(URL);
dataSource.setUsername(USER);
dataSource.setPassword(PASSWORD);
dataSource.setInitialSize(initSize);
dataSource.setMinIdle(minIdle);
dataSource.setMaxIdle(maxIdle);
dataSource.setMaxTotal(maxTotal);
dataSource.setMaxWaitMillis(maxWait);
} catch (IOException e) {
e.printStackTrace();
}
}
public static Connection getConnection(){
Connection connection =null;
try {
connection = dataSource.getConnection();
return connection;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public static void close(Connection cn , Statement st, ResultSet rs){
try {
if(cn!=null&&!cn.isClosed()){
cn.close();
}
if( st!=null&&!st.isClosed()){
st.close();
}
if(rs!=null&&!rs.isClosed()){
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
System.out.println(getConnection());
}
}
db.properties 配置文件
##连接四要素
driver=oracle.jdbc.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:xe
user=system
password=123456
##连接池参数配置
##初始连接数
initSize=4
##最小空闲连接
minIdle=4
##最大空闲连接
maxIdle=5
##最大连接数
maxTotal=8
##超时等待时间
maxWait=10000
具体实现
package cn.lyc.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import cn.lyc.entity.Claxx;
import cn.lyc.entity.Student;
import cn.lyc.util.DBUtils;
/**
- getGeneratedKeys()获取主键值的方法
- 先生产班级id
- 再通过班级id赋值给学生表的班级id
- @author JLB
*/
public class GetPrimaryKey {
@SuppressWarnings("resource")
public void insertClassAndStudent(Student s, Claxx c){
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
String clxxSql = "insert into claxx values(seq_claxx_index.nextval,?)";
String stuSql = "insert into students values(seq_students_index.nextval,?,?)";//seq_students_index数据库建的序列
try {
conn = DBUtils.getConnection();
ps =conn.prepareStatement(clxxSql, new String[]{"cid"});//这里比较特殊,有多个重载的方法(注意不要调错方法咯!)
ps.setString(1, c.getCname());
ps.executeUpdate();//执行语句
rs = ps.getGeneratedKeys();//返回的结果
int key = 0;
if(rs.next()){
key = rs.getInt(1);//获取claxx主键cid
}
ps = conn.prepareStatement(stuSql);
ps.setString(1, s.getSname());
ps.setInt(2, key);//给学生表里的cid赋值
ps.executeUpdate();//执行语句
System.out.println("执行结束!!");
} catch (SQLException e) {
e.printStackTrace();
}finally{
DBUtils.close(conn, ps, rs);
}
}
public static void main(String[] args) {
GetPrimaryKey gpk = new GetPrimaryKey();
Claxx c = new Claxx();
c.setCname("ui班");
Student s = new Student();
s.setSname("小熙");
gpk.insertClassAndStudent(s, c);
}
}
数据库查询结果: