I have an EMPLOYEE table that has 4 fields; ID, NAME, AGE, SALARY. ID is unique and auto-increment.
Below is the code to insert a row in the table, using Spring's JDBCTemplate. Please suggest, how can I auto increment ID field.
String sql = "insert into employee values (?,?,?,?)"
jdbcTemplate.update( sql, ID, bean.getName(), bean.getAge(), bean.getSalary())
I see, you tag your question Oracle, use Oracle sequence then.
String sql = "insert into Employee values (id_seq.nextval, ?, ?, ?)";
jdbcTemplate.update(sql, bean.getName(), bean.getAge(), bean.getSalary());
Ref: How to create Sequence in Oracle.
Just add following code to your domain:
Ref: http://docs.spring.io/spring/docs/2.5.x/reference/jdbc.html#jdbc-auto-genereted-keys
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
final String INSERT_SQL = "insert into my_test (name) values(?)";
final String name = "Rob";
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(
new PreparedStatementCreator() {
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
PreparedStatement ps =
connection.prepareStatement(INSERT_SQL, new String[] {"id"});
ps.setString(1, name);
return ps;
}
},
keyHolder);
Related
I have a customer table and an address table. I'm trying to automatically insert the primary key value into the address table. Initially, I had it the other way around and it worked, however, the relationship was wrong since I wasn't able to delete cascade when a customer was deleted. Information inserts into the customer table but not the address table. This is what I have. Any insight would be appreciated.
/**
* Add a new customer.
* #param customer The customer to be added.
* #return customerId.
* #throws SQLException If an error happens.
*/
public int addCustomer(Customer customer) throws SQLException {
// first insert the address of the customer
//int addressId = addAddress(customer.getAddress());
// next insert the customer
var sql = "INSERT INTO customer (customerId, customerName, active, createdBy)" +
" VALUES (?, ?, ?, ?)";
var statement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
statement.setInt(1, 0);
statement.setString(2, customer.getName());
//statement.setInt(3, addressId);
statement.setBoolean(3, customer.isActive());
statement.setString(4, customer.getCreatedBy());
statement.execute();
var generatedKeys = statement.getGeneratedKeys();
generatedKeys.next();
return (int) generatedKeys.getLong(1);
}
/**
* Add a new address to the database.
* #param address The address to be added.
* #throws SQLException if an error happens.
*/
public void addAddress(Address address) throws SQLException {
int customerId = addCustomer(address.getCustomer());
var sql = "INSERT INTO address (addressId, customerId, address, address2, cityId, countryId, postalCode, phone, createdBy) " +
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
var statement = connection.prepareStatement(sql);
statement.setInt(1, 0);
statement.setInt(2, customerId);
statement.setString(3, address.getAddress());
statement.setString(4, address.getAddress2());
statement.setInt(5, address.getCity().getId());
statement.setInt(6, address.getCountry().getId());
statement.setString(7, address.getPostalCode());
statement.setString(8, address.getPhone());
statement.setString(9, address.getCreatedBy());
statement.execute();
}
Got some help with just updating the delete customer method so it deletes the associated address along with the customer.
enter code here
public void deleteCustomer(Customer customer) throws Exception {
var appointments =
appointmentRepository.findCustomerAppointments(customer.getId());
if(!appointments.isEmpty()){
throw new RuntimeException("Constraint Violation");
}
var deleteAddress = "DELETE FROM address WHERE addressId = ?";
var statementDeleteAddress = connection.prepareStatement(deleteAddress);
statementDeleteAddress.setInt(1, customer.getAddress().getId());
statementDeleteAddress.execute();
var sql = "DELETE FROM customer WHERE customerId = ?";
var statement = connection.prepareStatement(sql);
statement.setInt(1, customer.getId());
statement.execute();
Is there any possibility to specify the sequence generator as a value for a column in SimpleJdbcInsert, JdbcTemplate, NamedParameterJdbcTemplate or any other class for batch execution?
e.g., I want to achieve the SQL to be generated by any of the above classes as:
INSERT INTO SOME_TABLE_NAME (ID, COLUMN_A,...) VALUES (SOME_SEQUENCE.NEXTVAL, 'value for column A', ...);
A sample code snippet is like:
import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
List<SomeTableEntity> listOfEntities; // received from method parameter
SimpleJdbcInsert sql = new SimpleJdbcInsert(dataSource).withTableName("SOME_TABLE_NAME");
SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(listOfEntities.toArray());
sql.executeBatch(batch);
I tried to trick the SimpleJdbcInsert as:
SqlParameterSource id = new MapSqlParameterSource("ID", "SOME_SEQUENCE.nextval"));
SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(listOfEntities.toArray());
List<SqlParameterSource> params = new ArrayList<>(batch.length + 1);
params.add(id);
for (SqlParameterSource param : batch)
{
params.add(param);
}
sql.executeBatch(params.toArray(new SqlParameterSource[] {}));
But not to a surprise, that didn't worked since the ID column is of type numeric and it tried to fill the value as "SOME_SEQUENCE.nextval" instead of evaluating the result of SOME_SEQUENCE.nextval.
PS: There are too many columns in the table and due to that I do not want to use a prepared statement solution
String sql = "INSERT INTO USER
(USER_PK, ACCOUNTNUMBER, FIRSTNAME, LASTNAME, EMAIL )
VALUES
(user.nextval, ?, ?, ?, ?)";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, accountNumber);
ps.setString(2, firstName);
ps.setString(3, lastName);
ps.setString(4, email);
I have the RAW(16) PK column in Oracle, and trying to insert into it using JDBC:
PreparedStatement stmt = connection.prepareStatement("insert into COUNTRY (id, state, version, code, name, nationality, issuing_entity, country) values (?, ?, ?, ?, ?, ?, ?, ?)");
UUID id = UUID.randomUUID();
stmt.setObject(1, id, Types.BINARY);
However, I am getting an exception:
java.sql.SQLException: Invalid column type
at oracle.jdbc.driver.OraclePreparedStatement.setObjectCritical(OraclePreparedStatement.java:8494)
at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:7995)
at oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:8559)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.setObject(OraclePreparedStatementWrapper.java:225)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.setObject(HikariProxyPreparedStatement.java)
at rw.gov.dgie.framework.test.AbstractTestCaseWithDB.tryToInsertCountry(AbstractTestCaseWithDB.java:78)
at rw.gov.dgie.framework.test.AbstractTestCaseWithDB.dbSetup(AbstractTestCaseWithDB.java:62)
at test.rw.gov.dgie.bms.terr.service.TestCountryService.init(TestCountryService.java:37)
I am getting the same exception when trying to use DbSetup for inserting test data.
Is there a way to make JDBC insert UUIDs into RAW(16) column?
I am using Oracle JDBC 12.2.0.1.0.
You must convert the UUID to a byte array. See the method asBytes how to do it.
After it the binding is a s simple as using setBytes.
Example
def stmt = con.prepareStatement("insert into TAB_UUID (id, uuid) values (?,?)")
// bind
stmt.setInt(1,1)
def uuid = UUID.randomUUID()
stmt.setBytes(2,asBytes(uuid))
def rowCount = stmt.executeUpdate()
Here just for case the link doesn't work the conversion method UUID to byte array
public static byte[] asBytes(UUID uuid) {
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(uuid.getMostSignificantBits());
bb.putLong(uuid.getLeastSignificantBits());
return bb.array();
}
Oracle has no real UUID datatype and dealing with RAW(16) is really a PITA.
What we do, is to pass the UUID as a string to a SQL statement that uses hextoraw():
String sql = "insert into foo (id) values (hextoraw(?))";
PreparedStatement pstmt = connection.prepareStatement(sql);
UUID uid = UUID.randomUUID();
pstmt.setString(1, uid.toString().replaceAll("-", ""));
getJdbcTemplate().update("INSERT INTO abc(abc_id, abc_uuid, "
+ "VALUES (?, ?)",
abcId, uuidToBytes(abcUuid))
Here's a helper method to converet UUID type to bytes.
private byte[] uuidToBytes(final UUID uuid) {
if (Objects.isNull(uuid)) {
return null;
}
final byte[] uuidAsBytes = new byte[16];
ByteBuffer.wrap(uuidAsBytes)
.order(ByteOrder.BIG_ENDIAN)
.putLong(uuid.getMostSignificantBits())
.putLong(uuid.getLeastSignificantBits());
return uuidAsBytes;
}
JdbcTemplate provides different methods for performing a DML operations like insert. Please, consider for instance update.
#MarmiteBomber provides in his/her answer all the necessary information for performing what you need, please, only wrap the code appropriately in the different artifacts defined by Spring.
For example, you can use PreparedStatementCreator, something like:
jdbcTemplate.update(new PreparedStatementCreator() {
#Override
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
PreparedStatement ps = con.prepareStatement("insert into TAB_UUID (id, uuid) values (?,?)");
ps.setInt(1,1);
UUID uuid = UUID.randomUUID();
ps.setBytes(2,asBytes(uuid));
return ps;
}
});
The code can be simplified using lambdas to:
jdbcTemplate.update(con -> {
PreparedStatement ps = con.prepareStatement("insert into TAB_UUID (id, uuid) values (?,?)");
ps.setInt(1,1);
UUID uuid = UUID.randomUUID();
ps.setBytes(2,asBytes(uuid));
return ps;
});
If you prefer, you can use PreparedStatementSetter instead:
jdbcTemplate.update("insert into TAB_UUID (id, uuid) values (?,?)", new PreparedStatementSetter() {
#Override
public void setValues(PreparedStatement ps) throws SQLException {
ps.setInt(1,1);
UUID uuid = UUID.randomUUID();
ps.setBytes(2, asBytes(uuid));
}
});
Again, the code can be simplified with lambdas:
jdbcTemplate.update("insert into TAB_UUID (id, uuid) values (?,?)", ps -> {
ps.setInt(1,1);
UUID uuid = UUID.randomUUID();
ps.setBytes(2, asBytes(uuid));
});
In both examples you explicitly invoke setBytes in the underlying prepared statement and use the asBytes method from the Marmite answer.
I want to insert two rows into master and detail table.
Master and detail table with autoincremented id.
CREATE TABLE MI_User (
id_user NUMBER(11) NOT NULL,
age NUMBER(3),
name_user varchar2(128),
constraint USER_PK PRIMARY KEY (id_user));
CREATE TABLE Friends (
id_friend NUMBER(11) not null,
name VARCHAR2(64),
id_user NUMBER(11) NOT NULL,
constraint FRIEND_PK PRIMARY KEY (id_friend)
);
Model classes are:
public class User {
private String id;
private Integer age;
private String name;
private ArrayList<Friend> friends;
}
public class Friend {
private Long id_user;
private String name;
}
There is example from Hibernate:
tx = session.beginTransaction();
User user = new User(name, age);
employeeID = (Integer) session.save(employee);
tx.commit();
I try to insert with JDBS:
conn = DriverManager
.getConnection("jdbc:oracle:thin:#localhost:1521:xe", "hr", "hr");
ps = conn
.prepareStatement("INSERT INTO MI_USER (BALANCE, AGE, NAME_USER, GENDER, COMPANY, EMAIL, ADDRESS)\n" +
" VALUES (?, ?, ?, ?, ?, ?, ?)");
ps.setDouble(1, user.getDoubleBallans());
ps.setInt(2, user.getAge());
ps.setString(3, user.getName());
ps.executeUpdate();
How to get id_user and insert row into detail table?
I think you can use ps.getGeneratedKeys() method and send Statement.RETURN_GENERATED_KEYS as second parameter in conn.prepareStatement() method.
I have a listener that listens a button and takes 3 texts fields from input to execute an update query. I want to execute the update but in the query to pass my local variables(name,city,salary).
What can i do this?
public void actionPerformed(ActionEvent arg0) {
final String name;
final String city;
final String salary;
name = (textFieldName.getText());
city = (textFieldCity.getText());
salary = (textFieldSalary.getText());
System.out.println(salary);
try {
Statement s = connection.createStatement();
s.executeUpdate("INSERT INTO users (name,city,salary) VALUES (name, city,salary)");
I'd go with a PreparedStatement
PreparedStatement s = connection.prepareStatement("INSERT INTO users (name,city,salary) VALUES (?, ?, ?)");
s.setString(1, name);
s.setString(2, city);
s.setString(3, salary);
boolean res = s.execute();
This approach is a bit better, quoting will be automatically managed and will prevent simple SQL Injection.