Spring mvc, jdbc template i generowanie klucza

0

Jak rozwiązać taki problem:

Mam taką klasę:

public class Customer{


    private int id;

    @NotNull
    @Size(min=2, max=15)
    private String name;
    @Min(value = 18)
    private int age;
    @Min(value = 1)
    private double salary;

    MultipartFile image;


taki kontroler do dodawania "Customeró" - z racji problemu nie jest on ukońćzony

@RequestMapping(value = "/customers/add", method = RequestMethod.GET)
	public String getAddNewCustomerForm(@ModelAttribute("customer") Customer customer) {
		return "add";
	}

	@RequestMapping(value = "/customers/add", method = RequestMethod.POST)
	public String processAddCustomerForm(@Valid @ModelAttribute("customer") Customer customer, BindingResult result, HttpServletRequest request) {

		MultipartFile customerImage = customer.getImage();
		String rootDirectory = request.getSession().getServletContext().getRealPath("/");

		if(result.hasErrors()){
			return "add";
		}
		else {

			repository.addCustomer(customer);
			if (customerImage!=null && !customerImage.isEmpty()) {
				try {
					customerImage.transferTo(new File(rootDirectory+"resources\\images\\"+customer.hashCode() + ".jpg"));
				} catch (Exception e) {
					throw new RuntimeException("Product Image saving failed", e);
				}
			}
			return "redirect:/customers";
		}
	}

taki formularz za pomocą którego daję obiekty do bazy danych i wyświetlam je potem w widoku /customers(skracam kod)

<div class="form-group">
                <label class="control-label col-lg-2" for="name">Name</label>
                <div class="col-lg-10">
                    <form:input id="name" path="name" type="text" class="form:input-large" />
                    <form:errors path="name" cssClass="text-danger"/>
                </div>
            </div>

            <div class="form-group">
                <label class="control-label col-lg-2" for="age">Age</label>
                <div class="col-lg-10">
                    <div class="form:input-prepend">
                        <form:input id="age" path="age" type="text" class="form:input-large"/>
                        <form:errors path="age" cssClass="text-danger"/>
                    </div>
                </div>
            </div>

            <div class="form-group">
                <label class="control-label col-lg-2" for="salary">Salary</label>
                <div class="col-lg-10">
                    <form:input id="salary" path="salary" type="text" class="form:input-large"/>
                    <form:errors path="salary" cssClass="text-danger"/>
                </div>
            </div>
            <div class="form-group">
                <label class="control-label col-lg-2" for="salary">Choose file</label>
                <div class="col-lg-10">
                    <form:input id="image" path="image" type="file" class="form:input-large" />
                </div>
            </div>
            <div class="form-group">
                <div class="col-lg-offset-2 col-lg-10">
                    <input type="submit" id="btnAdd" class="btn btn-primary" value ="Add"/>
                </div>
            </div>

Jak widać NIE OKREŚLAM W NIM ID, bo jest generowane automatycznie w bazie danych

CREATE TABLE CUSTOMERS(
   ID   INT              NOT NULL auto_increment,
   NAME VARCHAR (20)     NOT NULL,
   AGE  INT              NOT NULL,
   SALARY   DECIMAL (18, 2),       
   PRIMARY KEY (ID)
);

metoda sql dodawania Customera do bazy danych wygląda tak:

@Override
    public void addCustomer(Customer customer) {
        //language=SQL
        String SQL_INSERT_CUSTOMER="INSERT INTO CUSTOMERS(NAME,AGE,SALARY) VALUES (?,?,?)";

        String name = customer.getName();
        int age = customer.getAge();
        double salary = customer.getSalary();

        jdbcTemplate.update(SQL_INSERT_CUSTOMER,name,age,salary);
    }

Problem jest taki, nie chciałem obciążać się generowaniem klcza głównego i zepchnąłem to na bazę danych. Jednak teraz gdy w kontrolerze wyciągam dane z forumularza i nie mam tam ID to jest problem. Bo potrzebuję unikalnego kodu aby przypisać do Customera obrazek.

Głupio mi dopisać w kontrolerze metodę, która będzie pytać o ID Customera, który dopiero został stworzony. Nie wiem jak tutaj automatycznie generować klucz główny aby od razu mieć do niego dostęp. Jakieś pomysły?

0

Czyli mam zmienić tą metodę sql na taką:

@Override
    public void addCustomer(Customer customer) {
        //language=SQL
        String SQL_INSERT_CUSTOMER="INSERT INTO CUSTOMERS(ID,NAME,AGE,SALARY) VALUES (?,?,?,?)";

        KeyHolder keyHolder = new GeneratedKeyHolder();
        String name = customer.getName();
        int age = customer.getAge();
        double salary = customer.getSalary();


        jdbcTemplate.update(SQL_INSERT_CUSTOMER,keyHolder.getKey(),name,age,salary);

return keyHolder.getKey()
    }

Tak?

A co jeśli odpalę aplikację od nowa i ona wywali błąd bo wygeneruje klucz, który jest już w baze danych(a trzymam w niej coś)

0

Po 1 to już wtedy nie zwracasz voida
Po 2 to zależy jak generujesz w bazie
Normalnie to się korzysta a autoinkrementacji klucza np. w PostgreSQL jest serial (lub bigserial) i on autoinkrementuje

0

No i mam tam włączoną autoinkrementację klucza(kod tworzacy tabele w sql jest w pierwszym poście). Tylko z tego powodu też rodzi się problem, bo skoro wydobywam dane z formularza i wstawiam je bez klucza do bazy danych i linijkę później potrzebuję id aby nadać unikalną nazwę obrazkowi. Głupio jest wsadzać obiekt do baz danych i od razu pytać o jego id. Rozumiesz?

0

No to przecież masz możliwosć zdobycia ID od razu wraz z insertem
Nie rozumiem za bardzo o co Ci chodzi

0

Jak?

W ten sposób? Na wzór tego?

String sql = "INSERT INTO table (column1, column2) values(?, ?)";
stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);


stmt.executeUpdate();
if(returnLastInsertId) {
   ResultSet rs = stmt.getGeneratedKeys();
    rs.next();
   auto_id = rs.getInt(1);
}

jak to zrobić używająć jdbc template?

Chyba np: w taki sposób(?)

package com.javacreed.examples.spring;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;

public class ExampleDao {

  @Autowired
  private JdbcTemplate jdbcTemplate;

  public long addNew(final String name) {
    final PreparedStatementCreator psc = new PreparedStatementCreator() {
      @Override
      public PreparedStatement createPreparedStatement(final Connection connection) throws SQLException {
        final PreparedStatement ps = connection.prepareStatement("INSERT INTO `names` (`name`) VALUES (?)",
            Statement.RETURN_GENERATED_KEYS);
        ps.setString(1, name);
        return ps;
      }
    };

    // The newly generated key will be saved in this object
    final KeyHolder holder = new GeneratedKeyHolder();

    jdbcTemplate.update(psc, holder);

    final long newNameId = holder.getKey().longValue();
    return newNameId;
  }
}
0

Skoro domyślasz się to może po prostu to zrób i jak będą problemy to spytasz się na forum?

0

Działa, ostateczna metoda powinna wyglądać tak:

 @Override
    public int addCustomer(Customer customer) {
        //language=SQL
        final String SQL_INSERT_CUSTOMER="INSERT INTO CUSTOMERS(NAME,AGE,SALARY) VALUES (?,?,?)";
        final String name = customer.getName();
        final int age = customer.getAge();
        final double salary = customer.getSalary();

        PreparedStatementCreator preparedStatementCreator = new PreparedStatementCreator() {
            @Override
            public PreparedStatement createPreparedStatement(final Connection connection) throws SQLException {
                final PreparedStatement preparedStatement = connection.prepareStatement(SQL_INSERT_CUSTOMER,
                        Statement.RETURN_GENERATED_KEYS);
                preparedStatement.setString(1,name);
                preparedStatement.setInt(2,age);
                preparedStatement.setDouble(3,salary);
                return preparedStatement;
            }
        };

        final KeyHolder holder = new GeneratedKeyHolder();
        jdbcTemplate.update(preparedStatementCreator,holder);
        return holder.getKey().intValue();
    }

1 użytkowników online, w tym zalogowanych: 0, gości: 1