Обработка исключений в спящем режиме - PullRequest
2 голосов
/ 10 октября 2011

У меня небольшой «сложный» вопрос.

Я использую Hibernate / JPA для транзакций с БД.

Я не администратор баз данных, и клиент использует мое приложение, веб-сервис RESTful. Моя проблема в том, что БД изменяется (не очень часто, но все равно меняется). Кроме того, клиент не всегда учитывает ввод для моего приложения (длина, тип и т. Д.). Когда это происходит, Hibernate создает исключение. Исключение трудно перевести и прочитать из журнала, потому что оно содержит вложенные исключения и состоит из большого количества текста: как я уже сказал, очень трудно понять.

Я хочу знать, возможно ли обрабатывать исключения на уровне сущности, возможно, выбрасывая индивидуальное исключение.

Благодарю за терпение и помощь заранее.

EDIT:

В общем-то, мне удалось сделать то, что я хотел, но я не был уверен, что все сделано правильно .

App.java

package com.mc;  

import org.hibernate.Session;  
import com.mc.stock.Stock;  
import com.mc.util.HibernateUtil;  
import javax.persistence.EntityManager;  

public class App {  

    public static void main(String[] args) {  
        Set<ConstraintViolation<Stock>> violations;
        validator = Validation.buildDefaultValidatorFactory().getValidator();
        Scanner scan = new Scanner(System.in);

        EntityManager em = null;

        System.out.println("Hibernate one to many (Annotation)");
        Session session = HibernateUtil.getSessionFactory().openSession();

        session.beginTransaction();


        Stock stock = new Stock();
        String nextLine = scan.nextLine();
        stock.setStockCode(nextLine.toString());
        nextLine = scan.nextLine();
        stock.setStockName(nextLine.toString());


        violations = validator.validate(stock);
        if (violations.size() > 0) {
            StringBuilder excepcion = new StringBuilder();
            for (ConstraintViolation<Stock> violation : violations) {
                excepcion.append(violation.getMessageTemplate());
                excepcion.append("\n");
            }
            System.out.println(excepcion.toString());
        }
        session.save(stock);
        session.getTransaction().commit();
    }  
}  

FieldMatch.java

package com.mc.constraints;  

import com.mc.constraints.impl.FieldMatchValidator;  

import javax.validation.Constraint;  
import javax.validation.Payload;  
import java.lang.annotation.Documented;  
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;  
import static java.lang.annotation.ElementType.TYPE;  
import java.lang.annotation.Retention;  
import static java.lang.annotation.RetentionPolicy.RUNTIME;  
import java.lang.annotation.Target;  

@Target({TYPE, ANNOTATION_TYPE})  
@Retention(RUNTIME)  
@Constraint(validatedBy = FieldMatchValidator.class)  
@Documented  
public @interface FieldMatch {  

    String message() default "{constraints.fieldmatch}";  

    Class<?>[] groups() default {};  

    Class<? extends Payload>[] payload() default {};  

    String first();  

    String second();  

    @Target({TYPE, ANNOTATION_TYPE})  
    @Retention(RUNTIME)  
    @Documented  
    @interface List {  

        FieldMatch[] value();  
    }  
}  

FieldMatchValidator.java

package com.mc.constraints.impl;  

import javax.validation.ConstraintValidator;  
import javax.validation.ConstraintValidatorContext;  
import com.mc.constraints.FieldMatch;  
import org.apache.commons.beanutils.BeanUtils;  

public class FieldMatchValidator implements ConstraintValidator<FieldMatch, Object> {  

    private String firstFieldName;  
    private String secondFieldName;  

    @Override  
    public void initialize(final FieldMatch constraintAnnotation) {  
        firstFieldName = constraintAnnotation.first();  
        secondFieldName = constraintAnnotation.second();  
    }  

    @Override  
    public boolean isValid(final Object value, final ConstraintValidatorContext context) {  
        try {  
            final Object firstObj = BeanUtils.getProperty(value, firstFieldName);  
            final Object secondObj = BeanUtils.getProperty(value, secondFieldName);  

            return firstObj == null && secondObj == null || firstObj != null && firstObj.equals(secondObj);  
        } catch (final Exception ignore) {  
            // ignore  
        }  
        return true;  
    }  
}  

Stock.java

package com.mc.stock;  

import com.mc.constraints.FieldMatch;  
import java.io.Serializable;  
import java.util.HashSet;  
import java.util.Set;  
import javax.persistence.Basic;  
import javax.persistence.Column;  
import javax.persistence.Entity;  
import javax.persistence.GeneratedValue;  
import javax.persistence.GenerationType;  
import javax.persistence.Id;  
import javax.persistence.NamedQueries;  
import javax.persistence.NamedQuery;  
import javax.persistence.OneToMany;  
import javax.persistence.SequenceGenerator;  
import javax.persistence.Table;  
import javax.xml.bind.annotation.XmlRootElement;  
import javax.xml.bind.annotation.XmlTransient;  
import org.hibernate.annotations.Cascade;  
import org.hibernate.annotations.CascadeType;  
import org.hibernate.validator.constraints.Length;  

@Entity  
@Table(name = "STOCK")  
@XmlRootElement  
@NamedQueries({  
    @NamedQuery(name = "Stock.findAll", query = "SELECT s FROM Stock s"),  
    @NamedQuery(name = "Stock.findByStockId", query = "SELECT s FROM Stock s WHERE s.stockId = :stockId"),  
    @NamedQuery(name = "Stock.findByStockCode", query = "SELECT s FROM Stock s WHERE s.stockCode = :stockCode"),  
    @NamedQuery(name = "Stock.findByStockName", query = "SELECT s FROM Stock s WHERE s.stockName = :stockName")})  
@FieldMatch.List({  
    @FieldMatch(first = "stockCode", second = "stockName", message = "Code and Stock must have same value")  
})  
public class Stock implements Serializable {  

    private static final long serialVersionUID = 1L;  
    @Id  
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_stock_id")  
    @SequenceGenerator(name = "seq_stock_id", sequenceName = "seq_stock_id", initialValue = 1, allocationSize = 1)  
    @Basic(optional = false)  
    @Column(name = "STOCK_ID", unique = true, nullable = false)  
    private Integer stockId;  
    @Column(name = "STOCK_CODE")  
    private String stockCode;  
    @Length(min = 1, max = 20, message = "{wrong stock name length}")  
    @Column(name = "STOCK_NAME")  
    private String stockName;  

    public Stock() {  
    }  

    public Stock(Integer stockId) {  
        this.stockId = stockId;  
    }  

    public Integer getStockId() {  
        return stockId;  
    }  

    public void setStockId(Integer stockId) {  
        this.stockId = stockId;  
    }  

    public String getStockCode() {  
        return stockCode;  
    }  

    public void setStockCode(String stockCode) {  
        this.stockCode = stockCode;  
    }  

    public String getStockName() {  
        return stockName;  
    }  

    public void setStockName(String stockName) {  
        this.stockName = stockName;  
    }  

    @Override  
    public int hashCode() {  
        int hash = 0;  
        hash += (stockId != null ? stockId.hashCode() : 0);  
        return hash;  
    }  

    @Override  
    public boolean equals(Object object) {  
        // TODO: Warning - this method won't work in the case the id fields are not set  
        if (!(object instanceof Stock)) {  
            return false;  
        }  
        Stock other = (Stock) object;  
        if ((this.stockId == null && other.stockId != null) || (this.stockId != null && !this.stockId.equals(other.stockId))) {  
            return false;  
        }  
        return true;  
    }  

    @Override  
    public String toString() {  
        return "com.mc.stock.Stock[ stockId=" + stockId + " ]";  
    }  
}  

HibernateUtil.java

package com.mc.util;  

import org.hibernate.SessionFactory;  
import org.hibernate.cfg.Configuration;  

public class HibernateUtil {  

    private static final SessionFactory sessionFactory = buildSessionFactory();  

    private static SessionFactory buildSessionFactory() {  
        try {  
            // Create the SessionFactory from hibernate.cfg.xml  
            return new Configuration().configure().buildSessionFactory();  
        } catch (Throwable ex) {  
            // Make sure you log the exception, as it might be swallowed  
            System.err.println("Initial SessionFactory creation failed." + ex);  
            throw new ExceptionInInitializerError(ex);  
        }  
    }  

    public static SessionFactory getSessionFactory() {  
        return sessionFactory;  
    }  

    public static void shutdown() {  
        // Close caches and connection pools  
        getSessionFactory().close();  
    }  
}  

Структура БД Oracle

CREATE TABLE stock  
(  
    STOCK_ID  NUMBER(5)  NOT NULL ,  
    STOCK_CODE  VARCHAR2(10)  NULL ,  
    STOCK_NAME  VARCHAR2(20)  NULL   
);  

ALTER TABLE stock  
    add CONSTRAINT PK_STOCK_ID  PRIMARY KEY (STOCK_ID);  

create sequence seq_stock_id   
   start with 1   
   increment by 1   
   nomaxvalue;  

Ответы [ 4 ]

2 голосов
/ 10 октября 2011

Я склонен сделать столько же проверки, прежде чем вы получите уровень БД.Взгляните на Hibernate Validator, http://www.hibernate.org/subprojects/validator.html, который является эталонной реализацией JSR-303.

Используя стандартные аннотации, вы можете применять ограничения и получать хорошие сообщения об ошибках, прежде чем пытаться поместить объекты в свойбаза данных.

Я полагаю, что это позволит вам выполнить проверку на уровне организации в соответствии с запросом.

0 голосов
/ 10 октября 2011

Согласно моему опыту, вы должны поймать исключение SQLException, и тогда вы легко сможете получить код ошибки SQL для конкретной базы данных. Например: ваша база данных mysql и вы получили код ошибки 1062. Таким образом, вы можете знать, что ошибка является Дублированной ошибкой входа. Вы можете проверить код ошибки mysql http://www.briandunning.com/error-codes/?source=MySQL

0 голосов
/ 10 октября 2011

Вы можете реализовать свой собственный SQLExceptionConverter и обрабатывать его так, как хотите.

Используйте свойство 'hibernate.jdbc.sql_exception_converter', чтобы установить свой собственный конвертер.

Я не могу найти больше документации по этому вопросу, вам нужно поискать реализации Hibernate, чтобы найти больше.

Кстати, почему у вас не может быть глобального фильтра, который перехватывает каждое исключение и решает, какое исключение перебрасывать как есть или генерировать новое исключение? Вы будете делать более или менее то же самое, даже если реализуете свой собственный SQLExceptionConverter.

0 голосов
/ 10 октября 2011

Я не уверен, что вы имеете в виду под "уровнем сущности", но уверен. Поместите try / catch вокруг кода, который вызывает Hibernate. Поймай Throwable и отбрось все, что хочешь. Хитрость заключается в том, чтобы найти причину, которая имеет смысл, за исключением того, что вы бросаете.

Конечно, один важный момент заключается в том, что вы должны проверить все вводимые данные.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...