如何修复SpringBoot应用程序中SimpleJdbcInsert中的错误

时间:2019-03-23 22:38:01

标签: java spring spring-boot jdbctemplate

我在Spring 5中学习Spring Boot阅读书。我尝试将数据插入H2嵌入式数据库。我使用SimpleJdbcInsert和executeAndReturnKey方法。

这里是构造函数:

 @Autowired
public JdbcOrderRepository(JdbcTemplate jdbc) {

this.orderInserter = new SimpleJdbcInsert(jdbc).withTableName("Taco_Order").usingGeneratedKeyColumns("id");
    this.orderTacoInserter = new SimpleJdbcInsert(jdbc).withTableName("Taco_Order_Tacos");
    this.objectMapper = new ObjectMapper();
}

以下是插入数据的方法:

@Override
public Order save(Order order) {

    order.setPlacedAt(new Date());
    long orderId = saveOrderDetails(order);
    order.setId(orderId);
    List<Taco> tacos = order.getTacos();

    for (Taco taco : tacos)
        saveTacoToOrder(taco, orderId);

    return order;
}

private long saveOrderDetails(Order order) {
    Map<String, Object> values = objectMapper.convertValue(order, Map.class);
    values.put("placedAt", order.getPlacedAt());
    long orderId = orderInserter.executeAndReturnKey(values).longValue();

    return orderId;
}

该字符串上有错误:

long orderId = orderInserter.executeAndReturnKey(values).longValue();

错误文字:

 There was an unexpected error (type=Internal Server Error, status=500).
PreparedStatementCallback; ???????? NULL ?? ????????? ??? ???? 
"DELIVERYNAME" NULL not allowed for column "DELIVERYNAME"; SQL statement: 
INSERT INTO Taco_Order (DELIVERYNAME, DELIVERYSTREET, DELIVERYCITY, 
DELIVERYSTATE, DELIVERYZIP, CCNUMBER, CCEXPIRATION, CCCVV, PLACEDAT) 
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?) [23502-197]; nested exception is 
org.h2.jdbc.JdbcSQLException: ???????? NULL ?? ????????? ??? ???? 
"DELIVERYNAME" NULL not allowed for column "DELIVERYNAME"; SQL statement: 
INSERT INTO Taco_Order (DELIVERYNAME, DELIVERYSTREET, DELIVERYCITY, 
DELIVERYSTATE, DELIVERYZIP, CCNUMBER, CCEXPIRATION, CCCVV, PLACEDAT) 
   VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?) [23502-197]

调试器中的Bur没问题: value参数已由值完全加载。 idea screensot

班级顺序:

@Data
public class Order {

@NotBlank(message = "Name is required")
private String name;

@NotBlank(message = "Name is required")
private String street;

@NotBlank(message = "Name is required")
private String city;

@NotBlank(message = "Name is required")
private String state;

@NotBlank(message = "Name is required")
private String zip;

@CreditCardNumber(message = "Not valid cc")
private String ccNumber;

@Pattern(regexp = "^(0[1-9]|1[0-2])([\\/])([1-9][0-9])$", message = "Must be formatted MM/YY")
private String ccExpiration;

@Digits(integer = 3, fraction = 0, message = "Invalid CVV")
private String ccCVV;

private Long id;
private Date placedAt;

List<Taco> tacos = new ArrayList<>();

public void addDesign(Taco design) {
    this.tacos.add(design);
}

}

如何解决此问题并使用SimpleJdbcInsert将数据插入H2数据库?

6 个答案:

答案 0 :(得分:1)

我今天也遇到同样的问题。我能够解决这个问题。

要解决此问题,请转到schema.sql(要在其中创建表的文件)并从Taco_Order表中的字段中删除传递。

从书中

  

SimpleJdbcInsert具有执行插入的几个有用方法:execute()和executeAndReturnKey()。两者都接受一个Map,其中map键对应于数据插入到的表中的列名。映射值将插入到这些列中。

键名称是Order.java中的字段

答案 1 :(得分:0)

我经历了屏幕截图,但看不到DELIVERYNAME列的任何值。

问题是由于运行插入操作的表不允许DELIVERYNAME列为空值。

解决此问题的方法:-

  1. 从表定义的列中删除“非空”约束。

  2. 如果不确定数据是否为空白,请从对象的成员中删除@NotBlank注释。

  3. 在“表”中的列名与“类/实体定义”中具有成员名的列名之间使用正确的映射。您可以使用@Column注释轻松地做到这一点。

根据您的代码和屏幕截图,据我所知,该问题是由于列名与对象成员之间的映射不正确引起的。 建议不要使用Spring Boot编码器的自动映射,而应使用@Column注释或通过休眠配置文件进行映射来手动进行映射。

答案 2 :(得分:0)

问题出在Order类中。这些应该反映相应表的列名。 例如:

私有字符串deliveryName; ->将映射到db中的deliveryName字段。

问题已经出现,因为在schema.sql中,该字段被命名为“ deliveryName”,而在配料类中,服装被命名为“ name”。

答案 3 :(得分:0)

这个答案是给那些遵循《春天在行动》一书中的例子的人的。在现实生活中您不会做这种事情,但是如果您是这本书的读者,可以替换掉它:

    Map<String, Object> values = objectMapper.convertValue(order, Map.class);
    values.put("placedAt", order.getPlacedAt());

与此:

        Map<String,Object> values = new HashMap<>();
        values.put("ID", order.getId());
        values.put("PLACEDAT", order.getPlacedAt());
        values.put("DELIVERYNAME", order.getName());
        values.put("DELIVERYSTREET", order.getStreet());
        values.put("DELIVERYCITY", order.getCity());
        values.put("DELIVERYSTATE", order.getState());
        values.put("DELIVERYZIP", order.getZip());
        values.put("CCNUMBER", order.getCcNumber());
        values.put("CCEXPIRATION", order.getCcExpiration());
        values.put("CCCVV", order.getCcCVV());

先前的答案提到更改模式,如果您将遵循下一章中的示例或使用jpa注释执行映射,则将导致问题,但是根据该书的作者,您不了解它们,因为它们将在下一章中介绍。章节。此外,您将不在下一章中使用JdbcOrderRepository类。

答案 4 :(得分:0)

Order类中的字段名称必须与表Taco_Order中的列名称相同。

@Data
public class Order {
    private Long id;

    private Date placedAt;

    @NotBlank(message = "Podanie imienia i nazwiska jest obowiazkowe")
    private String deliveryName;

    @NotBlank(message = "Podanie ulicy jest obowiązkowe")
    private String deliveryStreet;

    @NotBlank(message = "Podanie miasta jest obowiązkowe")
    private String deliveryCity;

    @NotBlank(message = "Podanie województwa jest obowiązkowe")
    private String deliveryState;

    @NotBlank(message = "Podanie kodu pocztowego jest obowiązkowe")
    private String deliveryZip;

    @CreditCardNumber(message = "To nie jest prawidłowy numer karty kredytowej")
    private String ccNumber;

    @Pattern(regexp = "^(0[1-9]|1[0-2])([\\/])([1-9][0-9])$", message = "Wartość musi być w formacie MM/RR")
    private String ccExpiration;

    @Digits(integer = 3, fraction = 0, message = "Nieprawidłowy kod CVV")
    private String ccCVV;

    public List<Taco> tacos = new ArrayList<>();

    public void addDesign(Taco design) {
        this.tacos.add(design);
    }

    public List<Taco> getTacos() {
        return tacos;
    }
}

答案 5 :(得分:0)

我今天遇到了同样的问题,我忘记做的只是将 order.html 文件中的字段更新为 deliveryName、deliveryCity 等。