返回数据库自动更新主键(getGeneratedKeys())

返回数据库自动更新主键
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对象。

数据库表设计

数据库表设计:
![数据库表](https://img-blog.csdnimg.cn/20190110112356550.?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyOTAyNDcw,size_16,col

完整代码如下:
实体类: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);
}

}

数据库查询结果:
结果

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_42902470/article/details/86249361