Spring MVC won't display correct database valu

2020-08-17 05:04发布

问题:

In my controller, put a value from a MySQL database into a ModelAndView object

There is a separate program that updates the table and the MVC is supposed to grab that value so there are no forms to update that table.

When the table is updated, and when I hit refresh on the browser, the values will not update on the page.

Controller

@SuppressWarnings("unchecked")
@Secured({ "ROLE_USER", "ROLE_ADMIN" })
@RequestMapping(value = { "/", "/welcome" }, method = RequestMethod.GET)
public ModelAndView defaultPage(@ModelAttribute("user") User user) {
    Collection<SimpleGrantedAuthority> authorities = (Collection<SimpleGrantedAuthority>) SecurityContextHolder
            .getContext().getAuthentication().getAuthorities();
    ModelAndView view = new ModelAndView("/hello");
    // Redirects to admin page if user has admin role
    if (authorities.toString().contains("ROLE_ADMIN")) {
        return new ModelAndView("redirect:/admin");
    }
    /////
    Authentication auth = SecurityContextHolder.getContext().getAuthentication();
    String userName = auth.getName();
    User userInfo = userDAO.getUserInfo(userName);
    System.out.println("Here's the thing " + userInfo.getLastname() + " " + userInfo.getUserDetails());
    Details details = userDAO.getDetailsInfo(userInfo.getUserDetails().getLastname(),
            userInfo.getUserDetails().getPostcode());
    Plugs plugs = userDAO.getPlugInfo(details.getMacAddress()); 
    String json = plugs.getJson();
    JSONObject obj = new JSONObject(json); //this is the value that is not updating
    String name = obj.getJSONObject("meta").getJSONObject("locate").getString("value");
    System.out.println(name); 
    view.addObject("json", obj);
    return view;
}

I know this is pretty looked down upon, but I putting that value in Javascript.

like this:

<c:set var="json" value="${json}"/> 

var __data__ = ${json};

Why won't the MVC display the correct value when the database is updated?

I want it to update on refresh

EDIT: I've disabled caching and cleared cache still have a problem. Any help?

回答1:

Definitely PersistenceContextType.EXTENDED scope is the root cause for your problem as you identified. The reason below:

With PersistenceContextType.TRANSACTION scope, Spring framework takes responsibility of managing the life cycle of the injected the entitymanager. The life of TRANSACTION scope is tied to the underlying transaction and upon commit/rollback of the transaction the entityManager is closed by the spring framework.

But with PersistenceContextType.EXTENDED scope, Spring framework takes responsibility of only injecting the entitymanager. The life cycle of EXTENDED scoped entity manager is not tied to the user transaction and it can span multiple transactions. It is up to the application/user to explicitly close the entityManager once we are done with it. If not it will remain open forever (or till Spring container is closed).

I presume in your userDAO you are not closing entityManager explicitly. And also 'userDAO' could be a singleton. So the same entityManager that got injected only once is being used across multiple calls (or http requests)

With this the entityManager' remains open forever and so when you try to access any object (User/Plugin/UserDetails) theentityManager` checks its first level cache, it will check its first level cache which it finds in it (that got loaded for the first time) and returns this object form its first level cache (which is stale) instead of hitting the database for the data.

And obviously with TRANSACTION scope the entityManager is closed by the Spring framework whenever transaction is completed (or method exits). This results in creating an entityManager for each request (in your case web request) hits the the database which has the updated data.

See if this link helps. http://forum.spring.io/forum/other-spring-related/ejb/18445-injection-of-persistencecontext-with-persistencecontexttype-extended



回答2:

So the solution I have has nothing to do with the code I posted, but in my UserDAO.java class.

Simple change.

From this:

@PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager em;

To this:

@PersistenceContext(type = PersistenceContextType.TRANSACTION)
private EntityManager em;

and it works. Thank for the people who commented and tried to help/

EDIT: I hate answering my own questions, so if someone could have an in depth explanation on why this works, I'll accept it as an answer.



回答3:

http://docs.oracle.com/javaee/6/tutorial/doc/gkjio.html

Disable the JPA second level cache otherwise the entity manager does not recognise changed data which was changed directly in the database Put

@Cacheable(false)

onto your entity