I want to update the mysql database in spring mybatis. I have couple of mapper interface and want to perform update using sqlsession.commit(). How can I define each of sqlsession?
#Transactional
public BookingRecord book(Person person, Hotel hotel, String id) {
List<Room> rooms = hotel.getRooms();
for (Room room : rooms) {
if (room.isAvailable()) {
if (person.getBalance() > room.getPrice()) {
// 开始订房
room.setAvailable(false); // 保留房间
person.setId(id);
person.setBalance(person.getBalance() - room.getPrice()); //转账
hotel.setBalance(hotel.getBalance() + room.getPrice()); //转账2
BookingRecord r = new BookingRecord(); //生成订单
r.setHotelName(hotel.getName()); //记录酒店名
r.setRoomNumber(room.getRoomNumber()); //记录房间号
r.setPersonId(person.getId()); //记录客人id
r.setStartDate(new Date());
personMapper.update(person);
brMapper.create(r);
hotelMapper.updateBalance(hotel);
roomMapper.update(room);
return r;
}
}
}
log.info(person.getName() + "successfully booked at " + hotel.getName());
return null;
}
#Transactional make this class transactional means spring will manage begin, commit and rollback procedure during executions. Transactions itself is a very wide area of research so I suggest you should read Spring Transaction to understand more about how Spring manages transaction. And in regards to your question, I suggest you should inject JDBC connection to this bean to perform begin, (commit or rollback) prophetically.
Related
Facing an issue while rollback saving data.
Problem:
In my java method there are three saving actions. Data save to different table. I want when a saving fails then all saved transaction will be rollback.
Example, there are three tables consist of master table and sub table. All table save in a method. APVoucherEntryDetails is the child table, when it saves fail then upper transactions should be rollback.
How can I do it ?
Thanks in advance
#Override
public ApiResponse saveVoucher(APVoucherBatch batch) {
APVoucherBatch savedBatch = voucherBatchRepo.save(batch); //table 1
//==========save entry=============
List<APVoucherEntry> entryList = batch.getEntryList();
for(APVoucherEntry info: entryList){
info.setVoucherBatch(savedBatch);
info.setBatchNo(savedBatch.getBatchNo());
APVoucherEntry savedEntry = entryRepo.save(info); //table 2
//==========save detail=============
List<APVoucherEntryDetails> detailsList = info.getDetailsList();
for(APVoucherEntryDetails dtl: detailsList){
dtl.setBatchList(savedBatch);
dtl.setEntryInfo(savedEntry);
detailsRepo.save(dtl); //table 3
}
}
return new ApiResponse();
}
I have 2 database one is mysql and other is postgree.
I tried to get postgree data from mysql transactional method.
#Transactional(value = "pg")
public List<String> getSubordinate(){
Query q1 = JPA.em().createNativeQuery("select vrs.subordinate_number, vrs.superior_number\n" +
"from view_reporting_structure vrs\n" +
"where vrs.superior_number = :personel_number");
q1.setParameter("personel_number","524261");
List<String> me = q1.getResultList();
return me;
}
}
from another method
#Transactional
public Result getOpenRequestList(){
Subordinate subordinate = new Subordinate();
List<String> subordinateData = subordinate.getSubordinate();
....
}
i got error
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'db_hcm.view_reporting_structure' doesn't exist
so my Postgre method recognized as mySQL transaction which is the view not exist in mySQL database. how do I get data from different presistence unit with 1 method?
I never did it (different databases), but I guess the following may work.
For example, you have the following data source definition in application.conf:
# MySql
db.mysql.driver=com.mysql.jdbc.Driver
... the rest of setting for db.mysql
# H2
db.postgre.driver=org.postgresql.Driver
... the rest of setting for db.postgre
Instead of using #Transactional annotation, manage a transaction explicitly and use JPA withTransaction API:
private static final String MYSQL_DB = "mysql";
private static final String POSTGRE_DB = "postgre";
public List<String> getSubordinate() {
JPA.withTransaction(MYSQL_DB, true/* this is read-only flag*/,
() -> {
Query q1 = JPA.em().createNativeQuery("select vrs.subordinate_number, vrs.superior_number\n" +
"from view_reporting_structure vrs\n" +
"where vrs.superior_number = :personel_number");
q1.setParameter("personel_number","524261");
List<String> me = q1.getResultList();
return me;
}
}
public Result getOpenRequestList(){
JPA.withTransaction(POSTGRE_DB, true/* this is read-only flag*/,
() -> {
Subordinate subordinate = new Subordinate();
List<String> subordinateData = subordinate.getSubordinate();
....
}
}
Note: I prefer always use withTransaction, since it allows better control of unhappy flow. You should wrap the call with try-catch. If JPA throws a run-time exception on commit, you can do proper error handling. In case of using #Transactional annotation, commit takes place after controller have finished and you cannot handle the error.
Not necessarily specific to dropwizard, but for the life of me I can't figure out how to easily create a healthcheck for mongodb. This is in java, using version 3.3.0 of mongodb's own java driver.
I was hoping there would be a method that doesn't change the state of the database if it succeeds, but also throws an Exception when the query (or connection, or whatever) fails in order to return a health or unhealthy state. Ideally I'd perform a find, but this doesn't throw an Exception as far as I can tell.
I would just list all collections in database like:
MongoClient client = new MongoClient(addr, opts);
MongoDatabase db = client.getDatabase(database);
try {
MongoIterable<String> allCollections = db.listCollectionNames();
for (String collection : allCollections) {
System.out.println("MongoDB collection: " + collection);
}
} catch (Exception me) {
// problems with mongodb
}
I have the following ManyToMany association within my Project:
Class User:
#ManyToMany(cascade=CascadeType.ALL)
#JoinTable(
joinColumns={#JoinColumn(name="user_id")},
inverseJoinColumns={#JoinColumn(name="antrag_id")}
)
private List<Antrag> antraege;
And Class Antrag:
#ManyToMany(mappedBy="antraege",cascade=CascadeType.ALL)
private List<User> users;
I am trying to correctly insert a new record, this - I think works not correctly. When I'm trying to "reselect" all Antraege of User, I am getting a NullPointerException on antraege.getUsers(). Only when I restart the java swing application, antraege.getUsers() doesn't return null.
Code for Inserting my new ManyToMany record:
Antrag antrag = new Antrag();
antrag.setBetreff(betreff);
antragBusiness.create(antrag);
betreuer.getAntraege().add(antrag);
currentUser.getAntraege().add(antrag);
userBusiness.update(betreuer);
userBusiness.update(currentUser);
Where my create method uses persist and the update method uses merge.
As I've said, they get inserted correctly into the database, but when I try to call:
List<Antrag> antraege = (List<Antrag>) user.getAntraege();
for(Antrag a : antraege){
News n = new News();
n.setDatum(a.getCreatedAt());
n.setStatus(a.isStatus());
n.setThema(a.getInfo());
List<User> beteiligte = a.getUsers();
System.out.println("Amount users " + beteiligte.size());
for (User z : beteiligte) {
System.out.println(z.getNachname() + " " + z.getId());
if(z.getId() != user.getId()){
n.setZustaendiger(z);
}
}
newsList.add(n);
}
-> Amount users returns 0 :(
So - in consequences: Antraege are added to Users, but users not to Antraege?
Edit: As it seems, my insertion of a new ManyToMany record is not correct.
Can anyone explain me the correct way ?
I am trying to learn how to work with hibernate, and until now i thought i was doing ok...
The problem is, i have a one to many relationship that i can't update/delete.
My DB is pretty basic, i have a ClientsBasic that has a one to many relationship with IndirectClients (which simply has a ClientsBasic ID and a URL, both keys because you can have for the same ID lots of URLs)
ClientBasic:
#OneToMany(fetch = FetchType.EAGER, mappedBy = "clientsBasic", cascade=CascadeType.ALL)
public List<IndirectClients> getIndirectClients() {
return this.indirectClients;
}
public void setIndirectClients(List<IndirectClients> indirectClients) {
// this.indirectClients = indirectClients;
this.indirectClients.clear();
this.indirectClients.addAll(indirectClients);
}
ClientDao:
public ClientsBasic save(ClientsBasic client) throws HibernateException {
Transaction tx = null;
tx = session.beginTransaction();
session.saveOrUpdate(client);
tx.commit();
log.info("Client saved with id: " + client.getClientId());
return client;
}
Now if i try to delete ClientsBasic, it will delete both ClientsBasic and all related indirectClients, so its working as expected, but if i simply try to update/delete and entry in indirectClients it doesn't work.
Example:
I create a new Client
ClientsBasic cb = new ClientsBasic("company_1", 1234, "company_1#email.com");
cbDao.save(cb);
And then a new Indirect Client
List<IndirectClients> indirectClientsSet= new ArrayList<IndirectClients>();
indirectClientsSet.add(new IndirectClients(new IndirectClientsId(cb.getClientId(), "www.url.test_1.com"), cb));
cb.setIndirectClients(indirectClientsSet);
cbDao.save(cb);
Now if i try to change the url like this
ClientsBasic cb = cbDao.findClientById(1);
List<IndirectClients> indC = cb.getIndirectClients();
indC.get(0).getId().setUrl("TEST");
cb.setIndirectClients(indC);
cbDao.save(cb);
no changes are made in the DB.
Can someone please help me?
Thank you.
If your IndirectClients is defined as an Entity it has its own life cycle, meaning you have to persist/delete instances separately from their ClientBasic parent.
If you want a scenario where all children are managed through their parent relation, consider using ElementCollection.
See also JPA: When to choose Multivalued Association vs. Element Collection Mapping