Hibernate: getting a record but it's being updated in the database?
For some reason Hibernate seems to be keeping my session open and updating the object without me explicitely invoking a save/update/saveorupdate. I guess the session is staying open and it's beeing marked as dirty.
However this is not the desired behaviour, so what's the cleanest way to fix this?
The issue seems to occur because I store a phone number without formatting in the database but the getter of the object returns a formatted telephone number.
My flow: go to a jsp => controller => service => dao
DAO getter function
if(userId != 0) {
return (User)dbFactory.get(User.class, userId);
}
return null;
The service just passes it to the controller and the controller puts te User object in the request scope. I display it on my JSP page using EL.
edit: I added the following: JSP:
<spring:bind path = "user.telephoneNumber">${user.telephoneNumber}</spring:bind>
Controller:
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(String.class, "telephoneNumber", new TelephoneNumberEditor(false));
}
The editor: public class TelephoneNumberEditor extends PropertyEditorSupport { private boolean isRequired = false;
public TelephoneNumberEditor(boolean isRequired) {
this.isRequired = isRequired;
}
public void setAsText(String text) throws IllegalArgumentException {
String s = null;
if (!this.isRequired && StringUtils.isBlank(text)) {
setValue("");
}
else
{
s = text.replace("(0)","");
s = s.replaceAll("[^0-9]", "");
setValue(s);
}
}
public String getAsText() {
String telephoneNumber = (String) getValue();
if(StringUtils.isBlank(telephoneNumber)){
return "";
} else {
try {
MaskFormatter formatter = new MaskFormatter("+AA AA AA AA AA");
formatter.setValueContainsLiteralCharacters(false);
return formatter.valueToString(telephoneNumber);
} catch (ParseException e) {
return "";
}
}
}
}
And in the controller I put the User obj开发者_如何学Cect in the request scope as user.
You can create another property (getter and setter) for the formatted value and mark it as transient (with @Transient
or by omitting it in your .hbm.xml
):
@Transient
public String getFormattedPhoneNumber() { ... }
public void setFormattedPhoneNumber(String number) { ... }
Alternatively, you can configure Hibernate access type to work with fields instead of properties - in that case your getters can return arbitrary representations.
EDIT: If you use Spring MVC databinding, you can implement your formatting logic in PropertyEditor
. Since formatting a phone number is a presentation concern, moving it to the presentation layer looks reasonable:
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(String.class, "phoneNumber",
new PropertyEditorSupport() { ... });
}
In this approach custom editor works automatically in the typical Spring from processing cycle (form is rendered with Spring form tags and data are bound to @ModelAttribute
upon POST). If you need to display formatted value manually (outside of form tags), you can use <spring:bind>
:
<spring:bind path = "user.phoneNumber">${status.displayValue}</spring:bind>
(or without user.
if inside <form:form>
, I guess)
If you want to make non-persistent changes to a persistent object you can explicitly kick it out of context with Session.evict(Object object)
. Hibernate will not persist any changes you make to it after that's done.
Something about the description of why it happens doesn't quite add up. Are you using property based access for persistence, and not using direct getters-setters? A getter that marks up the value might raise architectural objections but in and of itself shouldn't be causing persistence problems.
精彩评论