Transaction annotation in SpringBoot does not work - spring-boot

The Transaction annotation does not seem to work for me.
This code works (manually opening a transaction):
#Repository
public class PeoplePropertiesDaoHibernate implements PeoplePropertiesDao {
private static final Logger LOGGER = LoggerFactory.getLogger(PeoplePropertiesDaoHibernate.class);
private String lastQuery;
private EntityManager em;
#PersistenceContext(unitName="timesheetPersistence")
public void setEntityManager(EntityManager em) {
this.em = em;
}
#Qualifier("entityManager")
#Autowired
EntityManagerFactory emf;
#Override
public EntityManager getPersistenceContext()
{
return em;
}
public boolean isHoursManager(String peopleId) {
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
String query =
"select count(*) " +
"from supervisor " +
"where people_id = :manager ";
tx.begin();
Session s = (Session) em.getDelegate();
Integer count = 0;
count = (Integer) s.createSQLQuery(query)
.setParameter("manager", peopleId)
.uniqueResult();
tx.commit();
em.close();
LOGGER.debug("Count = " + count + " return " + (count > 0));
return count > 0;
}
}
This code also works (type = PersistenceContextType.EXTENDED:
#Repository
public class PeoplePropertiesDaoHibernate implements PeoplePropertiesDao {
private static final Logger LOGGER = LoggerFactory.getLogger(PeoplePropertiesDaoHibernate.class);
private String lastQuery;
private EntityManager em;
#PersistenceContext(unitName="timesheetPersistence", type = PersistenceContextType.EXTENDED)
public void setEntityManager(EntityManager em) {
this.em = em;
}
#Override
public EntityManager getPersistenceContext()
{
return em;
}
public boolean isHoursManager(String peopleId) {
String query =
"select count(*) " +
"from supervisor " +
"where people_id = :manager ";
Session s = (Session) em.getDelegate();
Integer count = 0;
count = (Integer) s.createSQLQuery(query)
.setParameter("manager", peopleId)
.uniqueResult();
LOGGER.debug("Count = " + count + " return " + (count > 0));
return count > 0;
}
This code with #Transactional gives the error: Session/EntityManager is closed; nested exception is java.lang.IllegalStateException: Session/EntityManager is closed
#Transactional
#Repository
public class PeoplePropertiesDaoHibernate implements PeoplePropertiesDao {
private static final Logger LOGGER = LoggerFactory.getLogger(PeoplePropertiesDaoHibernate.class);
private String lastQuery;
private EntityManager em;
#PersistenceContext(unitName="timesheetPersistence")
public void setEntityManager(EntityManager em) {
this.em = em;
}
#Override
public EntityManager getPersistenceContext()
{
return em;
}
public boolean isHoursManager(String peopleId) {
String query =
"select count(*) " +
"from supervisor " +
"where people_id = :manager ";
Session s = (Session) em.getDelegate();
Integer count = 0;
count = (Integer) s.createSQLQuery(query)
.setParameter("manager", peopleId)
.uniqueResult();
LOGGER.debug("Count = " + count + " return " + (count > 0));
return count > 0;
}
What is the cause of this?
EDIT: THIS WORKS!! Why would the session from the getDelegate() not use the transaction?
String query =
"select count(*) " +
"from Supervisor " +
"where people_id = :manager ";
Session s = (Session) em.getDelegate();
Integer count = 0;
count = ((Long)em.createQuery(query)
.setParameter("manager", peopleId)
.getSingleResult()).intValue()
;
LOGGER.debug("Count = " + count + " return " + (count > 0));
return count > 0;

Related

Drools decision table - rules not matching

I have a hello-world type spring/drools setup. The issue is no rules fire when in theory they should.
Decision Table:
Console output - server startup:
package com.example.drools;
//generated from Decision Table
import com.example.drools.TestRules;
// rule values at B9, header at B4
rule "_9"
when
$test:TestRules(number1 == 10)
then
$test.add("10");
end
Drools Config:
#Configuration
public class DroolsConfiguration
{
private final static String VALIDATION_RULES = "validation-rules.xls";
#Bean
public KieContainer validationRulesKieContainer() {
KieServices kieServices = KieServices.Factory.get();
Resource rules = ResourceFactory.newClassPathResource(VALIDATION_RULES);
compileXlsToDrl(rules);
KieFileSystem kieFileSystem = kieServices.newKieFileSystem().write(rules);
KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem);
KieBuilder builder = kieBuilder.buildAll();
KieModule kieModule = kieBuilder.getKieModule();
return kieServices.newKieContainer(kieModule.getReleaseId());
}
private static void compileXlsToDrl(Resource resource) {
try {
InputStream is = resource.getInputStream();
SpreadsheetCompiler compiler = new SpreadsheetCompiler();
String drl = compiler.compile(is, InputType.XLS);
System.out.println(drl);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Service:
#Service
public class ValidationRulesEngine
{
#Autowired
#Qualifier("validationRulesKieContainer")
private KieContainer validationKieContainer;
public void validate() {
KieSession kieSession = validationKieContainer.newKieSession();
kieSession.addEventListener(new DebugAgendaEventListener());
kieSession.addEventListener(new DebugRuleRuntimeEventListener());
TestRules tr = new TestRules(10, 20, 30);
kieSession.insert(tr);
int noOfRulesFired = kieSession.fireAllRules();
System.out.println("noOfRulesFired: " + noOfRulesFired);
System.out.println(tr);
System.out.println(tr.getRule());
}
}
TestRule - Fact:
public class TestRules
{
public int number1;
public int number2;
public int number3;
public List<String> rules = new ArrayList<String>();
public TestRules() {}
public TestRules(int number1, int number2, int number3)
{
super();
this.number1 = number1;
this.number2 = number2;
this.number3 = number3;
}
public void add(String rule) {
rules.add(rule);
}
public String getRule() {
return this.rules.size() > 0 ? this.rules.get(0) : "";
}
#Override
public String toString()
{
return "TestRules [number1=" + number1 + ", number2=" + number2 + ", number3=" + number3 + ", rules=" +
rules.stream().map(s -> s.toString()).collect(Collectors.joining(",")) + "]";
}
}
Console output - result:
2021-07-20 17:02:27.549 ERROR 20212 --- [nio-9016-exec-1] c.g.i.e.p.c.OfficeController : --> Rules Engine
==>[ObjectInsertedEventImpl: getFactHandle()=[fact 0:1:1539328290:1539328290:1:DEFAULT:NON_TRAIT:com.example.drools.TestRules:TestRules [number1=10, number2=20, number3=30, rules=]], getObject()=TestRules [number1=10, number2=20, number3=30, rules=], getKnowledgeRuntime()=KieSession[0], getPropagationContext()=PhreakPropagationContext [entryPoint=EntryPoint::DEFAULT, factHandle=[fact 0:1:1539328290:1539328290:1:DEFAULT:NON_TRAIT:com.example.drools.TestRules:TestRules [number1=10, number2=20, number3=30, rules=]], leftTuple=null, originOffset=-1, propagationNumber=2, rule=null, type=INSERTION]]
noOfRulesFired: 0
TestRules [number1=10, number2=20, number3=30, rules=]
2021-07-20 17:02:28.454 ERROR 20212 --- [nio-9016-exec-1] c.g.i.e.p.c.OfficeController : <-- Rules Engine
What am I missing?
This is no good:
$test:TestRules($test.number1 == 10, $test.number2 == 20)
You can't refer to $test before you declare it. The correct syntax is:
$test: TestRules( number1 == 10, number2 == 20 )
Fix your decision table from $test.number1 == $param to instead be number1 == $param. (And do the same for number2 adjacent.)
The rest looks fine, though I would suggest using a try-with-resources instead of a try-catch in your XLSX parsing method.

Field value in a Class does not get updated with Spring Boot MVC Controller

I have a Parcel Entity, and I am populating the fields through #PostMapping. The value Volume should be gotten from a method taking in values from the agruments in the constructor.
Controller Class:
#Controller
public class Controller {
#Value("#{${listOfBases}}")
private List<String> listOfBases;
#Value("#{${listOfDestinations}}")
private List<String> listOfDestinations;
#Autowired
ParcelRepository parcelRepository;
#GetMapping("/register_parcel")
public String showParcelRegistrationForm(Model model) {
Parcel parcel = new Parcel();
model.addAttribute("parcel", parcel);
model.addAttribute("listOfBases", listOfBases);
model.addAttribute("listOfDestinations", listOfDestinations);
return "parcel/register_form_parcel";
}
#PostMapping("register_parcel")
public String registerParcel(#ModelAttribute("parcel") Parcel parcel) {
System.out.println(parcel);
parcelRepository.save(parcel);
return "user/user_registration_success_form";
}
}
Parcel Class:
#Entity
public class Parcel {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
int id;
String length;
String width;
String height;
String weight;
String base;
String destination;
String creationDate;
String volume;
No args constructor:
public Parcel() {
creationDate = getCreationDateAndTime();
}
public Parcel(int id, String length, String width, String height, String weight, String base, String destination) {
this.id = id;
this.length = length;
this.width = width;
this.height = height;
this.weight = weight;
this.base = base;
this.destination = destination;
creationDate = getCreationDateAndTime();
volume = String.valueOf(calculateVolume(width, height, length));
}
Getters and Setters:
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getLength() {
return length;
}
public void setLength(String length) {
this.length = length;
}
public String getWidth() {
return width;
}
public void setWidth(String width) {
this.width = width;
}
public String getHeight() {
return height;
}
public void setHeight(String height) {
this.height = height;
}
public String getWeight() {
return weight;
}
public void setWeight(String weight) {
this.weight = weight;
}
public String getBase() {
return base;
}
public void setBase(String base) {
this.base = base;
}
public String getDestination() {
return destination;
}
public void setDestination(String destination) {
this.destination = destination;
}
public String getCreationDate() {
return creationDate;
}
public void setCreationDate(String creationDate) {
this.creationDate = creationDate;
}
public String getVolume() {
return volume;
}
public void setVolume(String volume) {
this.volume = volume;
}
private String getCreationDateAndTime() {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime now = LocalDateTime.now();
return dtf.format(now);
}
CalculateVolume method that is the root of the problem:
private int calculateVolume(String width, String height, String length) {
int w = Integer.parseInt(width);
int h = Integer.parseInt(height);
int l = Integer.parseInt(length);
return w * h * l;
}
But the value volume is null in my database. Even System.out.println(); in calculateVolume does not print anything on the console, but when I run create an instance in main, all runs fine and dandy.
Any ideas on how I should proceed, or is my question too vague?
Thank you
#Override
public String toString() {
return "Parcel{" +
"id=" + id +
", length='" + length + '\'' +
", width='" + width + '\'' +
", height='" + height + '\'' +
", weight='" + weight + '\'' +
", base='" + base + '\'' +
", destination='" + destination + '\'' +
", creationDate='" + creationDate + '\'' +
", volume='" + volume + '\'' +
'}';
}
}
Change Post method in your controller
from
public String registerParcel(#ModelAttribute("parcel") Parcel parcel)
to
public String registerParcel(#RequestBody Parcel parcel)

Partitions and JdbcPagingItemReader doesn't gives correct values

I am working on Spring Batch and Partition using the JdbcPagingItemReader, but I am only getting half records.
If I am expecting 100 thousand records instead getting only 50 thousand. What's wrong is happening
How to use Nested or Inner Query in OraclePagingQueryProvider ?
My Original Query
SELECT q.*
FROM (SELECT DEPT.ID id,
DEPT.CREATOR createdby,
DEPT.CREATE_DATE createddate,
DEPT.UPDATED_BY updatedby,
DEPT.LAST_UPDATE_DATE updateddate,
DEPT.NAME name,
DEPT.STATUS status,
statusT.DESCR statusdesc,
REL.ROWID_DEPT1 rowidDEPT1,
REL.ROWID_DEPT2 rowidDEPT2,
DEPT2.DEPT_FROM_VAL parentcid,
DEPT2.NAME parentname,
ROW_NUMBER() OVER (PARTITION BY DEPT.CREATE_DATE ORDER BY DEPT.ID) AS rn
FROM TEST.DEPT_TABLE DEPT
LEFT JOIN TEST.STATUS_TABLE statusT
ON DEPT.STATUS = statusT.STATUS
LEFT JOIN TEST.C_REL_DEPT rel
ON DEPT.ID = REL.ROWID_DEPT2
LEFT JOIN TEST.DEPT_TABLE DEPT2
ON REL.ROWID_DEPT1 = DEPT2.ID) q
WHERE rn BETWEEN ? AND ?; // ? will be fromValue to toValue
Code:
#Configuration
public class CustomerJob2 {
#Autowired
private JobBuilderFactory jobBuilderFactory;
#Autowired
private StepBuilderFactory stepBuilderFactory;
#Bean
public CustomerPartitioner customerPartitioner() {
return new CustomerPartitioner();
}
#Bean("readCustomerJob")
#Primary
public Job readCustomerJob() throws Exception {
return jobBuilderFactory.get("readCustomerJob")
.incrementer(new RunIdIncrementer())
.start(customerStepOne())
.build();
}
#Bean
public Step customerStepOne() throws Exception {
return stepBuilderFactory.get("customerStepOne")
.partitioner(slaveStep().getName(), customerPartitioner())
.step(slaveStep())
.gridSize(5)
.taskExecutor(new SimpleAsyncTaskExecutor())
.build();
}
// slave step
#Bean
public Step slaveStep() throws Exception {
return stepBuilderFactory.get("slaveStep")
.<Customer, Customer>chunk(3000)
.reader(pagingItemReader(null, null))
.writer(customerWriter())
.listener(customerStepOneExecutionListener())
.build();
}
// Reader
#Bean(destroyMethod = "")
#StepScope
public JdbcPagingItemReader<Customer> pagingItemReader(
#Value("#{stepExecutionContext['fromValue']}") Long fromValue,
#Value("#{stepExecutionContext['toValue']}") Long toValue) throws Exception {
System.out.println(" FROM = "+ fromValue + " TO VALUE ="+ toValue);
JdbcPagingItemReader<Customer> reader = new JdbcPagingItemReader<>();
reader.setDataSource(this.dataSource);
reader.setRowMapper(new CustomerRowMapper());
reader.setSaveState(false);
reader.setPageSize(3000);
// Sort Keys
Map<String, Order> sortKeys = new HashMap<>();
sortKeys.put("id", Order.ASCENDING);
OraclePagingQueryProvider queryProvider = new OraclePagingQueryProvider();
queryProvider.setSelectClause("q.* FROM ( SELECT Row_Number() OVER (ORDER BY party.ROWID_OBJECT) MyRow, "
+ " OTHER coumns in the Query");
queryProvider.setFromClause("**** "
+ "LEFT JOIN ********* "
+ "LEFT JOIN ********* "
+ "LEFT JOIN ********* ) q ");
queryProvider.setWhereClause("MyRow BETWEEN "+ fromValue + " AND "+ toValue);
queryProvider.setSortKeys(sortKeys);
reader.setQueryProvider(queryProvider);
reader.afterPropertiesSet();
return reader;
}
#Bean
public CustomerWriter customerWriter() {
return new CustomerWriter();
}
}
Partition Logic
public class CustomerPartitioner implements Partitioner{
private static final String CUSTOMER_CNT = "SELECT COUNT(party.IS) ***** COMPLEX JOIN";
#Autowired
#Qualifier("edrJdbcTemplate")
private JdbcTemplate jdbcTemplate;
#Override
public Map<String, ExecutionContext> partition(int gridSize) {
Long custCnt = jdbcTemplate.queryForObject(CUSTOMER_CNT, Long.class);
int toValue = 0;
int fromValue = 0;
int increment = 3000;
int counter = 0;
int temp = 0;
Map<String, ExecutionContext> partitionMap = new HashMap<>();
for (int i = 0; i < custCnt; i += increment) { // custCnt fives 100 thousand
counter++;
temp = i;
if(i == 0) {
fromValue = temp;
toValue = increment;
}else {
fromValue = toValue + 1;
toValue = fromValue + increment - 1;
}
ExecutionContext context = new ExecutionContext();
context.put("fromValue", fromValue);
context.put("toValue", toValue);
partitionMap.put("Thread--" + counter, context);
}
return partitionMap;
}
}
Here are the logs -
2020-06-22 22:44:14.750 INFO 15752 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=readCustomerJob]] launched with th
e following parameters: [{JobID=1592846054670, date=1592846054670}]
2020-06-22 22:44:14.790 INFO 15752 --- [ main] o.s.batch.core.job.SimpleStepHandler : Executing step: [customerStepOne]
Cust Count = 1035483
FROM = 6001 TO VALUE =9000
FROM = 0 TO VALUE =3000
FROM = 3001 TO VALUE =6000
FROM = 9001 TO VALUE =12000
2020-06-22 22:44:15.874 DEBUG 15752 --- [cTaskExecutor-4] o.s.b.i.database.JdbcPagingItemReader : Reading page 0
2020-06-22 22:44:15.874 DEBUG 15752 --- [cTaskExecutor-1] o.s.b.i.database.JdbcPagingItemReader : Reading page 0
2020-06-22 22:44:15.874 DEBUG 15752 --- [cTaskExecutor-2] o.s.b.i.database.JdbcPagingItemReader : Reading page 0
2020-06-22 22:44:15.874 DEBUG 15752 --- [cTaskExecutor-3] o.s.b.i.database.JdbcPagingItemReader : Reading page 0

How to export huge result set from database into several csv files and zip them on the fly?

I need to create a REST controller which extracts data from a database and write it into CSV files that will ultimately be zipped together. Each CSV file should contain exactly 10 lines. Eventually all CSV files should be zipped into a one zip file. I want everything to happen on the fly, meaning - saving files to a temporary location on the disk is not an option. Can someone provide me with an example?
I found a very nice code to export huge amount of rows from database into several csv files and zip it.
I think this is a nice code that can assist alot of developers.
I have tested the solution and you can find the entire example at : https://github.com/idaamit/stream-from-db/tree/master
The conroller is :
#GetMapping(value = "/employees/{employeeId}/cars") #ResponseStatus(HttpStatus.OK) public ResponseEntity<StreamingResponseBody> getEmployeeCars(#PathVariable int employeeId) {
log.info("Going to export cars for employee {}", employeeId);
String zipFileName = "Cars Of Employee - " + employeeId;
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_TYPE, "application/zip")
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + zipFileName + ".zip")
.body(
employee.getCars(dataSource, employeeId));
The employee class, first checks if we need to prepare more than one csv or not :
public class Employee {
public StreamingResponseBody getCars(BasicDataSource dataSource, int employeeId) {
StreamingResponseBody streamingResponseBody = new StreamingResponseBody() {
#Override
public void writeTo(OutputStream outputStream) throws IOException {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
String sqlQuery = "SELECT [Id], [employeeId], [type], [text1] " +
"FROM Cars " +
"WHERE EmployeeID=? ";
PreparedStatementSetter preparedStatementSetter = new PreparedStatementSetter() {
public void setValues(PreparedStatement preparedStatement) throws SQLException {
preparedStatement.setInt(1, employeeId);
}
};
StreamingZipResultSetExtractor zipExtractor = new StreamingZipResultSetExtractor(outputStream, employeeId, isMoreThanOneFile(jdbcTemplate, employeeId));
Integer numberOfInteractionsSent = jdbcTemplate.query(sqlQuery, preparedStatementSetter, zipExtractor);
}
};
return streamingResponseBody;
}
private boolean isMoreThanOneFile(JdbcTemplate jdbcTemplate, int employeeId) {
Integer numberOfCars = getCount(jdbcTemplate, employeeId);
return numberOfCars >= StreamingZipResultSetExtractor.MAX_ROWS_IN_CSV;
}
private Integer getCount(JdbcTemplate jdbcTemplate, int employeeId) {
String sqlQuery = "SELECT count([Id]) " +
"FROM Cars " +
"WHERE EmployeeID=? ";
return jdbcTemplate.queryForObject(sqlQuery, new Object[] { employeeId }, Integer.class);
}
}
This class StreamingZipResultSetExtractor is responsible to split the csv streaming data into several files and zip it.
#Slf4j
public class StreamingZipResultSetExtractor implements ResultSetExtractor<Integer> {
private final static int CHUNK_SIZE = 100000;
public final static int MAX_ROWS_IN_CSV = 10;
private OutputStream outputStream;
private int employeeId;
private StreamingCsvResultSetExtractor streamingCsvResultSetExtractor;
private boolean isInteractionCountExceedsLimit;
private int fileCount = 0;
public StreamingZipResultSetExtractor(OutputStream outputStream, int employeeId, boolean isInteractionCountExceedsLimit) {
this.outputStream = outputStream;
this.employeeId = employeeId;
this.streamingCsvResultSetExtractor = new StreamingCsvResultSetExtractor(employeeId);
this.isInteractionCountExceedsLimit = isInteractionCountExceedsLimit;
}
#Override
#SneakyThrows
public Integer extractData(ResultSet resultSet) throws DataAccessException {
log.info("Creating thread to extract data as zip file for employeeId {}", employeeId);
int lineCount = 1; //+1 for header row
try (PipedOutputStream internalOutputStream = streamingCsvResultSetExtractor.extractData(resultSet);
PipedInputStream InputStream = new PipedInputStream(internalOutputStream);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(InputStream))) {
String currentLine;
String header = bufferedReader.readLine() + "\n";
try (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {
createFile(employeeId, zipOutputStream, header);
while ((currentLine = bufferedReader.readLine()) != null) {
if (lineCount % MAX_ROWS_IN_CSV == 0) {
zipOutputStream.closeEntry();
createFile(employeeId, zipOutputStream, header);
lineCount++;
}
lineCount++;
currentLine += "\n";
zipOutputStream.write(currentLine.getBytes());
if (lineCount % CHUNK_SIZE == 0) {
zipOutputStream.flush();
}
}
}
} catch (IOException e) {
log.error("Task {} could not zip search results", employeeId, e);
}
log.info("Finished zipping all lines to {} file\\s - total of {} lines of data for task {}", fileCount, lineCount - fileCount, employeeId);
return lineCount;
}
private void createFile(int employeeId, ZipOutputStream zipOutputStream, String header) {
String fileName = "Cars for Employee - " + employeeId;
if (isInteractionCountExceedsLimit) {
fileCount++;
fileName += " Part " + fileCount;
}
try {
zipOutputStream.putNextEntry(new ZipEntry(fileName + ".csv"));
zipOutputStream.write(header.getBytes());
} catch (IOException e) {
log.error("Could not create new zip entry for task {} ", employeeId, e);
}
}
}
The class StreamingCsvResultSetExtractor is responsible for transfer the data from the resultset into csv file. There is more work to do to handle special character set which are problematic in csv cell.
#Slf4j
public class StreamingCsvResultSetExtractor implements ResultSetExtractor<PipedOutputStream> {
private final static int CHUNK_SIZE = 100000;
private PipedOutputStream pipedOutputStream;
private final int employeeId;
public StreamingCsvResultSetExtractor(int employeeId) {
this.employeeId = employeeId;
}
#SneakyThrows
#Override
public PipedOutputStream extractData(ResultSet resultSet) throws DataAccessException {
log.info("Creating thread to extract data as csv and save to file for task {}", employeeId);
this.pipedOutputStream = new PipedOutputStream();
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
prepareCsv(resultSet);
});
return pipedOutputStream;
}
#SneakyThrows
private Integer prepareCsv(ResultSet resultSet) {
int interactionsSent = 1;
log.info("starting to extract data to csv lines");
streamHeaders(resultSet.getMetaData());
StringBuilder csvRowBuilder = new StringBuilder();
try {
int columnCount = resultSet.getMetaData().getColumnCount();
while (resultSet.next()) {
for (int i = 1; i < columnCount + 1; i++) {
if(resultSet.getString(i) != null && resultSet.getString(i).contains(",")){
String strToAppend = "\"" + resultSet.getString(i) + "\"";
csvRowBuilder.append(strToAppend);
} else {
csvRowBuilder.append(resultSet.getString(i));
}
csvRowBuilder.append(",");
}
int rowLength = csvRowBuilder.length();
csvRowBuilder.replace(rowLength - 1, rowLength, "\n");
pipedOutputStream.write(csvRowBuilder.toString().getBytes());
interactionsSent++;
csvRowBuilder.setLength(0);
if (interactionsSent % CHUNK_SIZE == 0) {
pipedOutputStream.flush();
}
}
} finally {
pipedOutputStream.flush();
pipedOutputStream.close();
}
log.debug("Created all csv lines for Task {} - total of {} rows", employeeId, interactionsSent);
return interactionsSent;
}
#SneakyThrows
private void streamHeaders(ResultSetMetaData resultSetMetaData) {
StringBuilder headersCsvBuilder = new StringBuilder();
for (int i = 1; i < resultSetMetaData.getColumnCount() + 1; i++) {
headersCsvBuilder.append(resultSetMetaData.getColumnLabel(i)).append(",");
}
int rowLength = headersCsvBuilder.length();
headersCsvBuilder.replace(rowLength - 1, rowLength, "\n");
pipedOutputStream.write(headersCsvBuilder.toString().getBytes());
}
}
In order to test this, you need to execute http://localhost:8080/stream-demo/employees/3/cars

spring-data-jpa insert an entire entity

I'm new to spring-data-jpa and I've been doing just fine with reading records out of a database but now I would like to insert records. I would like to follow my same pattern of using the repository class along with a query to do the insertion. Is there a way similar to this post https://stackoverflow.com/a/24848086/3299397 where I can insert a record but instead of explicitly specifying each value I simply pass to the function an entity object and insert the entire object? Here is what I have so far.
Entity Class:
package blah.blah.blah;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
#Entity
#Table(name = "MESSAGE")
public class Message implements Serializable {
#Id
// #GeneratedValue(generator = "system-uuid")
// #GenericGenerator(name = "system-uuid", strategy = "uuid")
#Column(name = "MESSAGE_GUID")
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid")
private String messageGuid;
#Column(name = "MESSAGE_TYPE_CD")
private Long messageTypeCd;
#Column(name = "SENDER_GUID")
private String SenderGuid;
#Column(name = "MESSAGE_TITLE")
private String messageTitle;
#Column(name = "MESSAGE_STATUS_CD")
private Long messageStatusCd;
#Column(name = "ACTIVATED_DT")
private Date activatedDt;
#Column(name = "DEACTIVATED_DT")
private Date deactivatedDt;
#Column(name = "CREATE_BY")
private String createBy;
#Column(name = "CREATE_DT")
private Date createDt;
#Column(name = "UPDATE_BY")
private String updateBy;
#Column(name = "UPDATE_DT")
private Date updateDt;
// required by JPA
public Message() {
}
#SuppressWarnings("all")
public Message(
String messageGuid,
Long messageTypeCd,
String SenderGuid,
String messageTitle,
Long messageStatusCd,
Date activatedDt,
Date deactivatedDt,
String createBy,
Date createDt,
String updateBy,
Date updateDt) {
super();
this.messageGuid = messageGuid;
this.messageTypeCd = messageTypeCd;
this.SenderGuid = SenderGuid;
this.messageTitle = messageTitle;
this.messageStatusCd = messageStatusCd;
this.activatedDt = activatedDt;
this.deactivatedDt = deactivatedDt;
this.createBy = createBy;
this.createDt = createDt;
this.updateBy = updateBy;
this.updateDt = updateDt;
}
public String getMessageGuid() {
return messageGuid;
}
public void setMessageGuid(String messageGuid) {
this.messageGuid = messageGuid;
}
public Long getMessageTypeCd() {
return messageTypeCd;
}
public void setMessageTypeCd(Long messageTypeCd) {
this.messageTypeCd = messageTypeCd;
}
public String getSenderGuid() {
return SenderGuid;
}
public void setSenderGuid(String senderGuid) {
SenderGuid = senderGuid;
}
public String getMessageTitle() {
return messageTitle;
}
public void setMessageTitle(String messageTitle) {
this.messageTitle = messageTitle;
}
public Long getMessageStatusCd() {
return messageStatusCd;
}
public void setMessageStatusCd(Long messageStatusCd) {
this.messageStatusCd = messageStatusCd;
}
public Date getActivatedDt() {
return activatedDt;
}
public void setActivatedDt(Date activatedDt) {
this.activatedDt = activatedDt;
}
public Date getDeactivatedDt() {
return deactivatedDt;
}
public void setDeactivatedDt(Date deactivatedDt) {
this.deactivatedDt = deactivatedDt;
}
public String getCreateBy() {
return createBy;
}
public void setCreateBy(String createBy) {
this.createBy = createBy;
}
public Date getCreateDt() {
return createDt;
}
public void setCreateDt(Date createDt) {
this.createDt = createDt;
}
public String getUpdateBy() {
return updateBy;
}
public void setUpdateBy(String updateBy) {
this.updateBy = updateBy;
}
public Date getUpdateDt() {
return updateDt;
}
public void setUpdateDt(Date updateDt) {
this.updateDt = updateDt;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((SenderGuid == null) ? 0 : SenderGuid.hashCode());
result = prime * result + ((activatedDt == null) ? 0 : activatedDt.hashCode());
result = prime * result + ((createBy == null) ? 0 : createBy.hashCode());
result = prime * result + ((createDt == null) ? 0 : createDt.hashCode());
result = prime * result + ((deactivatedDt == null) ? 0 : deactivatedDt.hashCode());
result = prime * result + ((messageGuid == null) ? 0 : messageGuid.hashCode());
result = prime * result + ((messageStatusCd == null) ? 0 : messageStatusCd.hashCode());
result = prime * result + ((messageTitle == null) ? 0 : messageTitle.hashCode());
result = prime * result + ((messageTypeCd == null) ? 0 : messageTypeCd.hashCode());
result = prime * result + ((updateBy == null) ? 0 : updateBy.hashCode());
result = prime * result + ((updateDt == null) ? 0 : updateDt.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Message other = (Message) obj;
if (SenderGuid == null) {
if (other.SenderGuid != null)
return false;
} else if (!SenderGuid.equals(other.SenderGuid))
return false;
if (activatedDt == null) {
if (other.activatedDt != null)
return false;
} else if (!activatedDt.equals(other.activatedDt))
return false;
if (createBy == null) {
if (other.createBy != null)
return false;
} else if (!createBy.equals(other.createBy))
return false;
if (createDt == null) {
if (other.createDt != null)
return false;
} else if (!createDt.equals(other.createDt))
return false;
if (deactivatedDt == null) {
if (other.deactivatedDt != null)
return false;
} else if (!deactivatedDt.equals(other.deactivatedDt))
return false;
if (messageGuid == null) {
if (other.messageGuid != null)
return false;
} else if (!messageGuid.equals(other.messageGuid))
return false;
if (messageStatusCd == null) {
if (other.messageStatusCd != null)
return false;
} else if (!messageStatusCd.equals(other.messageStatusCd))
return false;
if (messageTitle == null) {
if (other.messageTitle != null)
return false;
} else if (!messageTitle.equals(other.messageTitle))
return false;
if (messageTypeCd == null) {
if (other.messageTypeCd != null)
return false;
} else if (!messageTypeCd.equals(other.messageTypeCd))
return false;
if (updateBy == null) {
if (other.updateBy != null)
return false;
} else if (!updateBy.equals(other.updateBy))
return false;
if (updateDt == null) {
if (other.updateDt != null)
return false;
} else if (!updateDt.equals(other.updateDt))
return false;
return true;
}
#Override
public String toString() {
return "Message [messageGuid=" + messageGuid + ", messageTypeCd=" + messageTypeCd + ", SenderGuid="
+ SenderGuid + ", messageTitle=" + messageTitle + ", messageStatusCd=" + messageStatusCd
+ ", activatedDt=" + activatedDt + ", deactivatedDt=" + deactivatedDt + ", createBy=" + createBy
+ ", createDt=" + createDt + ", updateBy=" + updateBy + ", updateDt=" + updateDt + "]";
}
}
Repository Class:
package blah.blah.blah;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
#Repository
public interface MessageRepository extends JpaRepository<Message, String> {
#Query("SELECT "
+ "m "
+ "FROM Message m "
+ "WHERE messageGuid = :messageGuid")
List<Message> findByMessageGuid(#Param("messageGuid") String messageGuid);
// THIS DOES NOT WORK!
// #Query("INSERT "
// + "INTO Message")
// void insertMessage(#Param("myMessage") Message myMessage);
}
Service Class:
package blah.blah.blah;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class MessageServiceImpl implements MessageService {
private static final Logger log = LoggerFactory.getLogger(MessageServiceImpl.class);
#Autowired
private MessageRepository messageRepository;
#Override
public void getMessage(String messageGuid) {
List<Message> messageList = messageRepository.findByMessageGuid(messageGuid);
for (Message message : messageList)
log.info("\n\n" + message.toString() + "\n\n");
}
Component Class:
#Component
public class MessageComponentThingy {
#Autowired
MessageService messageService;
public void thisIsALongExample() {
messageService.getMessage("34A02DCF520F0831E053870910ACED7A");
}
}
This works for me when I want to read a record from the database...
Update Note: Please note that I am not necessarily concerned with doing 'Native Queries' I would just like to keep the same general pattern as what is shown in my Repository class. I would not reject an answer that uses a Native Query though. It honestly doesn't matter to me.
I didn't realize how simple this was. I am already inheriting the JpaRepository inside my repository class. JpaRepository has a method called 'save'. So you simply call that method. Everything works now....
I added new code below to the Service class (there's a new put method for the insert) and to the Component class (you can see me call the service classes put method). Hope this helps someone in the future.
Entity Class:
package blah.blah.blah;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
#Entity
#Table(name = "MESSAGE")
public class Message implements Serializable {
#Id
// #GeneratedValue(generator = "system-uuid")
// #GenericGenerator(name = "system-uuid", strategy = "uuid")
#Column(name = "MESSAGE_GUID")
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid")
private String messageGuid;
#Column(name = "MESSAGE_TYPE_CD")
private Long messageTypeCd;
#Column(name = "SENDER_GUID")
private String SenderGuid;
#Column(name = "MESSAGE_TITLE")
private String messageTitle;
#Column(name = "MESSAGE_STATUS_CD")
private Long messageStatusCd;
#Column(name = "ACTIVATED_DT")
private Date activatedDt;
#Column(name = "DEACTIVATED_DT")
private Date deactivatedDt;
#Column(name = "CREATE_BY")
private String createBy;
#Column(name = "CREATE_DT")
private Date createDt;
#Column(name = "UPDATE_BY")
private String updateBy;
#Column(name = "UPDATE_DT")
private Date updateDt;
// required by JPA
public Message() {
}
#SuppressWarnings("all")
public Message(
String messageGuid,
Long messageTypeCd,
String SenderGuid,
String messageTitle,
Long messageStatusCd,
Date activatedDt,
Date deactivatedDt,
String createBy,
Date createDt,
String updateBy,
Date updateDt) {
super();
this.messageGuid = messageGuid;
this.messageTypeCd = messageTypeCd;
this.SenderGuid = SenderGuid;
this.messageTitle = messageTitle;
this.messageStatusCd = messageStatusCd;
this.activatedDt = activatedDt;
this.deactivatedDt = deactivatedDt;
this.createBy = createBy;
this.createDt = createDt;
this.updateBy = updateBy;
this.updateDt = updateDt;
}
public String getMessageGuid() {
return messageGuid;
}
public void setMessageGuid(String messageGuid) {
this.messageGuid = messageGuid;
}
public Long getMessageTypeCd() {
return messageTypeCd;
}
public void setMessageTypeCd(Long messageTypeCd) {
this.messageTypeCd = messageTypeCd;
}
public String getSenderGuid() {
return SenderGuid;
}
public void setSenderGuid(String senderGuid) {
SenderGuid = senderGuid;
}
public String getMessageTitle() {
return messageTitle;
}
public void setMessageTitle(String messageTitle) {
this.messageTitle = messageTitle;
}
public Long getMessageStatusCd() {
return messageStatusCd;
}
public void setMessageStatusCd(Long messageStatusCd) {
this.messageStatusCd = messageStatusCd;
}
public Date getActivatedDt() {
return activatedDt;
}
public void setActivatedDt(Date activatedDt) {
this.activatedDt = activatedDt;
}
public Date getDeactivatedDt() {
return deactivatedDt;
}
public void setDeactivatedDt(Date deactivatedDt) {
this.deactivatedDt = deactivatedDt;
}
public String getCreateBy() {
return createBy;
}
public void setCreateBy(String createBy) {
this.createBy = createBy;
}
public Date getCreateDt() {
return createDt;
}
public void setCreateDt(Date createDt) {
this.createDt = createDt;
}
public String getUpdateBy() {
return updateBy;
}
public void setUpdateBy(String updateBy) {
this.updateBy = updateBy;
}
public Date getUpdateDt() {
return updateDt;
}
public void setUpdateDt(Date updateDt) {
this.updateDt = updateDt;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((SenderGuid == null) ? 0 : SenderGuid.hashCode());
result = prime * result + ((activatedDt == null) ? 0 : activatedDt.hashCode());
result = prime * result + ((createBy == null) ? 0 : createBy.hashCode());
result = prime * result + ((createDt == null) ? 0 : createDt.hashCode());
result = prime * result + ((deactivatedDt == null) ? 0 : deactivatedDt.hashCode());
result = prime * result + ((messageGuid == null) ? 0 : messageGuid.hashCode());
result = prime * result + ((messageStatusCd == null) ? 0 : messageStatusCd.hashCode());
result = prime * result + ((messageTitle == null) ? 0 : messageTitle.hashCode());
result = prime * result + ((messageTypeCd == null) ? 0 : messageTypeCd.hashCode());
result = prime * result + ((updateBy == null) ? 0 : updateBy.hashCode());
result = prime * result + ((updateDt == null) ? 0 : updateDt.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Message other = (Message) obj;
if (SenderGuid == null) {
if (other.SenderGuid != null)
return false;
} else if (!SenderGuid.equals(other.SenderGuid))
return false;
if (activatedDt == null) {
if (other.activatedDt != null)
return false;
} else if (!activatedDt.equals(other.activatedDt))
return false;
if (createBy == null) {
if (other.createBy != null)
return false;
} else if (!createBy.equals(other.createBy))
return false;
if (createDt == null) {
if (other.createDt != null)
return false;
} else if (!createDt.equals(other.createDt))
return false;
if (deactivatedDt == null) {
if (other.deactivatedDt != null)
return false;
} else if (!deactivatedDt.equals(other.deactivatedDt))
return false;
if (messageGuid == null) {
if (other.messageGuid != null)
return false;
} else if (!messageGuid.equals(other.messageGuid))
return false;
if (messageStatusCd == null) {
if (other.messageStatusCd != null)
return false;
} else if (!messageStatusCd.equals(other.messageStatusCd))
return false;
if (messageTitle == null) {
if (other.messageTitle != null)
return false;
} else if (!messageTitle.equals(other.messageTitle))
return false;
if (messageTypeCd == null) {
if (other.messageTypeCd != null)
return false;
} else if (!messageTypeCd.equals(other.messageTypeCd))
return false;
if (updateBy == null) {
if (other.updateBy != null)
return false;
} else if (!updateBy.equals(other.updateBy))
return false;
if (updateDt == null) {
if (other.updateDt != null)
return false;
} else if (!updateDt.equals(other.updateDt))
return false;
return true;
}
#Override
public String toString() {
return "Message [messageGuid=" + messageGuid + ", messageTypeCd=" + messageTypeCd + ", SenderGuid="
+ SenderGuid + ", messageTitle=" + messageTitle + ", messageStatusCd=" + messageStatusCd
+ ", activatedDt=" + activatedDt + ", deactivatedDt=" + deactivatedDt + ", createBy=" + createBy
+ ", createDt=" + createDt + ", updateBy=" + updateBy + ", updateDt=" + updateDt + "]";
}
}
Repository Class:
package blah.blah.blah;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
#Repository
public interface MessageRepository extends JpaRepository<Message, String> {
#Query("SELECT "
+ "m "
+ "FROM Message m "
+ "WHERE messageGuid = :messageGuid")
List<Message> findByMessageGuid(#Param("messageGuid") String messageGuid);
}
Service Class:
package blah.blah.blah;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class MessageServiceImpl implements MessageService {
private static final Logger log = LoggerFactory.getLogger(MessageServiceImpl.class);
#Autowired
private MessageRepository messageRepository;
#Override
public void getMessage(String messageGuid) {
List<Message> messageList = messageRepository.findByMessageGuid(messageGuid);
for (Message message : messageList)
log.info("\n\n" + message.toString() + "\n\n");
}
public void putMessage(Message message) {
messageRepository.save(message);
System.out.println("\n\nInside putMessage\n\n");
}
}
Component Class:
#Component
public class MessageComponentThingy {
#Autowired
MessageService messageService;
public void thisIsALongExample() {
messageService.getMessage("34A02DCF520F0831E053870910ACED7A");
Message message = new Message();
message.setMessageTypeCd(1L);
message.setSenderGuid("test");
message.setMessageTitle("test title");
message.setMessageStatusCd(1L);
message.setActivatedDt(new Date());
message.setDeactivatedDt(new Date());
message.setCreateBy("me");
message.setCreateDt(new Date());
message.setUpdateBy("me");
message.setUpdateDt(new Date());
messageService.putMessage(message);
}
}

Resources