Adding @Convert on column increases execution time

2019-04-02 18:13发布

问题:

I have the following entity:

@Data
@Entity
@Table(name="\"Customer\"")
public class Customer {
    @Id
    @SequenceGenerator(name="customer_id_seq",
            sequenceName="customer_id_seq",
            allocationSize=1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE,
            generator="customer_id_seq")
    private long id;
    private String firstName;
    @Convert(converter = LastNameEncryption.class)
    private String lastName;
}

Where LastNameEncryption.java is:

public class LastNameEncryption implements AttributeConverter<String,String> {

    private static SecretKeySpec secretKey;
    private final static String peselKey = "somekey";

    @Override
    public String convertToDatabaseColumn(String attribute) {
        try
        {
            setKey();
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            return Base64.getEncoder().encodeToString(cipher.doFinal(attribute.getBytes("UTF-8")));
        }
        catch (Exception e)
        {
            System.out.println("Error while encrypting: " + e.toString());
        }
        return null;

    }

    public String convertToEntityAttribute(String dbData) {
        try {
            setKey();
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            return new String(cipher.doFinal(Base64.getDecoder().decode(dbData)));
        }
        catch (Exception e)
        {
            System.out.println("Error while decrypting: " + e.toString());
        }
        return null;

    }

    public static void setKey() {
        MessageDigest sha = null;
        byte[] key;
        try {
            key = peselKey.getBytes("UTF-8");
            sha = MessageDigest.getInstance("SHA-1");
            key = sha.digest(key);
            key = Arrays.copyOf(key, 16);
            secretKey = new SecretKeySpec(key, "AES");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }  catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

}

Which should act as an ecnryption/decryption mechanism.

However, when I added this, the execution time of the simple queries increased from around 200ms to 5.5s (original topic here). I then found out, that when I comment the @Comment(...) annotation out, the query runs smoothly again.

Am I making any mistake, or is this normal behaviour?

NOTE

When I compared times of execution, there was only 3 entities in the table. Here is the log of execution time of the methods:

Execution time of convertToEntityAttribute: 5193
Execution time of convertToEntityAttribute: 0
Execution time of convertToEntityAttribute: 0
Execution time of convertToEntityAttribute: 0

For some reason, it takes almost 5.2s to encrypt for the first time - then, the time is smaller than 1 millisecond.

回答1:

Use jvisualvm (included in oracle jvm distribution) to pinpoint what is slow.

Use the Sampler tab, click on the CPU button just before triggering the slow operation (once without the @Convert, once with the annotation), and click on the Stop and then snapshot button when the operation is finished. Then compare both execution profile. You'll see exactly what method is taking time.

It could be a lazy initialization the first time you use the encryption tool, or hibernate, or anything else.

If you have a hard time analyzing the cpu sampling result, do not hesitate to come back here and update your question with it (you can export the snapshot).


Not related to your issue, i'm not sure it is advised to ignore exception at conversion (you return null in case of exception) : you might lose data.

Also, avoid doing that :

 System.out.println("Error while encrypting: " + e.toString());

For example, in case of NullPointerException, you'll get on the console : Error while encrypting: java.lang.NullPointerException: null. A nullpointer is really simple to fix, provided you have the stacktrace. Here you will have to guess where it happened.