Jiayi Zhou Jiayi Zhou - 1 month ago 10
Java Question

Java spring mvc using hibernate to do update

I started to develop APIs for iOS app using Java Spring MVC two months ago.
I'll explain my question with an example for clarification purpose.

Let's say I want to update a user's name.
My mySQL user table has columns: id, user_id, email, display_name.
My approach was:


  1. define user:



User.java:

package bean;
public class User {

String displayName;
String email;
String userId;

getters/setters...
}


2.define a DAO:

UserDao.java:

package dao;
import bean.StandardResponse;

public interface UserDao {
public StandardResponse updateUserName(String user_id,String userName);
}


UserDaoImpl.java:

package implement;
import bean.User;
import common.DatabaseConnect;

public UserDaoImpl implements UserDao {
private DatabaseConnect dbConnect;

public UserDaoImpl(DatabaseConnect dbConnect) {
this.dbConnect = dbConnect;
}

public StandardResponse updateUserName(userId,userName) {
if ((userId == null || userId.isEmpty()) ||(userName == null || userName.isEmpty())) return new StandardResponse("Error","Parameters not set!");
String sql = null;
Statement smt = dbConnect.createDataBaseConnectResourse();
StandardResponse result = new StandardResponse("Error","Fail to update the record!");
sql = "update User set user_name="+userName+" where user_id='"+userId+"'";
int updateResult = 0;
try {
updateResult = smt.executeUpdate(sql);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
dbConnect.closeDatabaseConnectResource();
}
if (updateResult == 1) {
result = new StandardResponse("Success","The record has been updated!");
}

return result;
}
}


3.controller

import org.springframework.stereotype.Controller;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import bean.StandardResponse;
import bean.User;
import common.DatabaseConnect;
import common.SpringApplicationContext;
import dao.UserDao;
import implement.UserDAOImpl;

@Controller
@RestController
@RequestMapping("user")
public class UserController {

DatabaseConnect dbConnect = SpringApplicationContext.getApplicationContext().getBean("databaseConnect", DatabaseConnect.class);
UserDao uiObject = new UserDaoImpl(dbConnect);

@RequestMapping(value = "/updateUserName", method = RequestMethod.POST)
public StandardResponse updateUserName(HttpServletRequest request, HttpServletResponse reponses, Model model) {
StandardResponse srObject = uiObject.updateUserName(request.getparameter("userId"),request.getParameter("userName"));
return srObject;
}
}


I just put the crucial classes here. I believe you can understand what I am doing here. So if someone access the URL:****/user/updateUserName providing the userId and userName, he can update the user name of that record. It is functionalbe.

I used the same approach and finished the whole project. It is working. Then, I asked an experienced programmer to look at my code since I figured out all these based on my own understanding. I would like to know how did they do in industry. He gave me some valuable comments.


  1. The whole structure is wrong. I shouldn't have logics in my dao. I should at least have dao, service and action layers. dao only handles database access, service handles all the logic and action handels communication and decide which service to call.

  2. It is very bad approach to hand written SQL in the code. I should use Hibernate.

  3. I should use control inverse and dependency injection.(I am not dealing with this in this post.)



So I started to update my codes to use Hibernate.


  1. define user:



User.java:

package model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="User")
public class User {

@Id
@Column(name="id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;

@Column(name = "user_id")
private String userId;

@Column(name = "user_name")
private String displayName;

@Column(name = "email")
private String emai;

all getters/setters...
}



  1. dao:



UserDao.java:

package dao;
import model.User;
import java.util.List;
public interface UserDAO {

public void updateUser(User p);
other methods....

}


UserDaoImpl.java

package dao;
import model.User;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.stereotype.Repository;

import model.User;

@Repository
public class PersonDAOImpl implements PersonDAO {

private SessionFactory sessionFactory;

public void setSessionFactory(SessionFactory sf){
this.sessionFactory = sf;
}

@Override
public void updatePerson(Person p) {
Session session = this.sessionFactory.getCurrentSession();
session.update(p);
}

implementations of other methods....

}



  1. service:



UserService.java:

package service;

import java.util.List;

import model.User;

public interface UserService {

public void updateUser(User p);
other methods....

}


UserServiceImpl.java:

package service;

import java.util.List;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import dao.UserDAO;
import model.User;

@Service
public class UserServiceImpl implements UserService {

private UserDAO userDAO;

public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}

@Override
@Transactional
public void updateUser(User p) {
this.userDAO.updateUser(p);
}

implementation of other methods...

}


Now, I just need to write a class to handle the request and call this updateUser service. The whole structure looks better than mine. However, the request won't gave me the whole user object. All I can get is user_id and user_name. I am also not allowed to put logics in dao. So I have to query the table first to get the whole user object and then update the user_name. Comparing to what I used to do, one SQL handles the update. Now using Hibernate, I need 1 query and 1 update.

I found a solution on StackOverflow that I can use HQL to do this in one step. But I though the purpose for using Hibernate is to free us from writing the SQL. If I need to write HQL, why don't I just keep using the writing SQL approach.

So is there a way to do update with Hibernate without query the table first in this structure? Or this is a trade-off for better structure?

I am sorry that I used a really long example for this question. But I couldn't think of other ways to explain the whole story clearly.

Answer

So is there a way to do update with Hibernate without query the table first in this structure? Or this is a trade-off for better structure? Thereis NO tradeoff, you can do updates with HQL(Hibernate Query Language) as well like how you do in SQL.

You can look at the following code:

UserDAOImpl class:

    @Repository
    //you are calling this in ur code as PersonDAOImpl..change it to UserDAOImpl
    public class UserDAOImpl implements UserDAO {

        private SessionFactory sessionFactory;

        public void setSessionFactory(SessionFactory sf){
            this.sessionFactory = sf;
        }

        @Override
        public int updateUser(String userId, String userName) {
            Session session = this.sessionFactory.getCurrentSession();
         Query query = session.createQuery("update User set userName =:userName where userId = :userName ");
         query.setString("userName", userName);  
         query.setString(userName, userName);  
         int result = query.executeUpdate();
         return result;
        }
    }

UserServiceImpl class:

@Service
public class UserServiceImpl implements UserService {

    private UserDAO userDAO;

    public void setUserDAO(UserDAO userDAO) {
        this.userDAO = userDAO;
    }

    @Override
    @Transactional
    public void updateUserName(String userId, String userName) {

        if(userId !=null && userName != null) {
                int result = this.userDAO.updateUser(userId, userName);

           if(result==0) //userid not available {
                //if userid is NOT available, what to do? check your requirement and handle properly
           }

           } 
       } else {
            //throw exception
       }
    }
    implementation of other methods...
}

Controller Class:

@Controller
@RestController
@RequestMapping("user")
public class UserController {

  @Autowired
  private UserService userService;

  @RequestMapping(value = "/updateUserName", method = RequestMethod.POST)
  public StandardResponse updateUserName(HttpServletRequest request, HttpServletResponse reponses, Model model) {
    StandardResponse srObject = userService.updateUserName(request.getparameter("userId"),request.getParameter("userName"));
    return srObject;
  }
}