Detailed explanation with chart, with picture description, the following is the text description, it may be a little difficult to understand

The final keyword can be assigned in any of the following ways: Explicit assignment: Private Final Integer Code = 1 Static code block/code block assignment constructor assignmentCopy the code

How to use Mybatis when storing enumeration classes directly into database? Mybatis acts as a middleman between Java and the database, automatically converting enumerations to strings when stored and strings when retrieved. How does Mybatis work?

Store: The default enumeration converter for Mybatis is EnumTypeHandler, which takes the enumeration name as a value and stores it in the database. Name () Mybatis has another enumeration converter, EnumOrdinalTypeHandler, which takes the value of the enumerated ordinal and stores it into the database. To switch:

Explicitly declared Mybatis enumeration converter, default is EnumTypeHandler default - enum type - handler: org. Apache. Ibatis. The EnumOrdinalTypeHandler

Name and ordinal are defined in the Enum abstract class, and all enumeration classes actually inherit from Enum, so every enumeration object has a name and ordinal. And the enumeration Enum parent overrides the toString() method. The actual return is name.

Remove:

How do I turn stored values into enumerations?

Again, EnumTypeHandler and EnumOrdinalTypeHandler must do it for us.

1. How do you make ordinal? How is EnumOrdinalTypeHandler handled?

EnumOrdinalTypeHandler extends from the BaseTypeHandler class. Enumeration conversion class, MyBatis provides TypeHandler interface to perform type conversion.

The toOrdinalEnum () method in the getNullableResult() method is called to fetch data from the database, which fetches ordianl’s corresponding Enum object directly from the ENums object. Enums is an array of enumerated objects.

When did enums come?

When Mybatis starts, the enumeration handler is initialized. Type.getenumconstants () calls the getEnumConstantsShared () method, in which the values() method is retrieved by reflection if it is an enumeration, and finally an array of enum objects.

Decompilation shows that the values array of the enumeration is loaded in a static code block.

2. How does name change? How does EnumTypeHandler work?

EnumTypeHandler also inherits from BaseTypeHandler. The getNullableResult() method is also implemented to convert names when data is retrieved from the database. In this method, we use the Enum. ValueOf (type, name) method, which gets an enumeration instance based on the enumeration name. The enumConstantDirectory() method in Class is eventually called

The enumeration object is stored in the Map by using the enumeration name() as the key, the enumeration object itself as the value, and then the enumeration object is directly retrieved by map.get (name). However, neither EnumTypeHandler nor EnumOrdinalTypeHandler handler is easy to use. In actual development, we often use fields defined by ourselves, such as code and desc, instead of ordinal or name.

Custom enumeration converter:

The core idea is copy! We can copy it using the model Enumordinary TypeHandler. Then let Mybatis convert by our converter. Mybatis provides the TypeHandler interface, but there are few methods in this interface. We can inherit the BaseTypeHandler like EnumOrdinalTypeHandler. 2. Specify type-handlers-package to tell Mybatis where to find our custom converter. 3. Use MappedTypes{Enum. Class} on the converter to specify which enumerated class to handle.

When we set the value, we will find that the ordianl method of enumeration is called. How can we set the custom field and how to obtain it? Right. Reflection. For more generality, you can annotate fields that you want to store in and out of the database by using annotations.

Ok, for Mybatis when working with enumerations, using our enumeration type handler, how can it know which field of the enumeration to operate on? Mark the field with an annotation and then use reflection to get which field contains the annotation. So let’s define the annotation class first.

So let’s write our custom MyEnumTypeHandler and see how it handles loading and unloading. Deposit:

Remove:

Is there any doubt? Where do enum and type come from? Like EnumOrdianlTypeHandler, we have no enums and type initialized in its constructor.

Summary:

Custom enumeration handler file: myEnumTypeHandler.java

package com.jt.mybatisenum.handler; import com.jt.mybatisenum.annotation.EnumValue; import com.jt.mybatisenum.enumj.WeekDayEnum; import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.MappedTypes; import java.lang.reflect.Field; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; /** * @author jiatai.hu * @version 1.0 * @date 2021/2/410:59 */ @mappedTypes (weekdayene.class) public class MyEnumTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E> { private final Class<E> type; private final E[] enums; public MyEnumTypeHandler(Class<E> type) { if (type == null) { throw new IllegalArgumentException("Type argument cannot be null"); } this.type = type; this.enums = type.getEnumConstants(); if (this.enums == null) { throw new IllegalArgumentException(type.getSimpleName() + " does not represent an enum type."); } } @Override public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException { Field[] declaredFields = parameter.getClass().getDeclaredFields(); for (Field declaredField : declaredFields) { EnumValue annotation = declaredField.getAnnotation(EnumValue.class); if (annotation == null){ continue; } declaredField.setAccessible(true); Object paramValue = null; ParamValue = declaredField.get(parameter); // Obtain the value of the EnumValue annotation field. } catch (IllegalAccessException e) { e.printStackTrace(); } ps.setObject(i, paramValue); return; } } @Override public E getNullableResult(ResultSet rs, String columnName) throws SQLException { Field[] declaredFields = type.getDeclaredFields(); Field enumField = null; Object value4Db = null; for (Field declaredField : declaredFields) { EnumValue annotation = declaredField.getAnnotation(EnumValue.class); if (annotation == null){ continue; } enumField = declaredField; value4Db = rs.getObject(columnName,enumField.getType()); break; } if (enumField == null){ return getResultByOrdinal(rs.getInt(columnName), rs.wasNull()); } enumField.setAccessible(true); for (E anEnum : enums) { try { Object value = enumField.get(anEnum); if (value.equals(value4Db)){ return anEnum; } } catch (IllegalAccessException e) { e.printStackTrace(); } } return getResultByOrdinal(rs.getInt(columnName), rs.wasNull()); } private E getResultByOrdinal(int anInt, boolean b) { int ordinal = anInt; if (ordinal == 0 && b) { return null; } return toOrdinalEnum(ordinal); } @Override public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return getResultByOrdinal(rs.getInt(columnIndex), rs.wasNull()); } @Override public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return getResultByOrdinal(cs.getInt(columnIndex), cs.wasNull()); } private E toOrdinalEnum(int ordinal) { try { return enums[ordinal]; } catch (Exception ex) { throw new IllegalArgumentException("Cannot convert " + ordinal + " to " + type.getSimpleName() + " by ordinal value.", ex); }}}Copy the code

EnumValue.java

package com.jt.mybatisenum.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author jiatai.hu * @version 1.0 * @date 2021/2/4 11:19 */ @target (elementtype.field) @Retention(RetentionPolicy.RUNTIME) public @interface EnumValue { }Copy the code

WeekDayEnum.java

package com.jt.mybatisenum.enumj; import com.jt.mybatisenum.annotation.EnumValue; import lombok.Getter; @getter Public enum WeekDayEnum {MONDAY(1," MONDAY "), TUESDAY(2," TUESDAY "), WEDNESDAY(3," WEDNESDAY "), THURSDAY(4," THURSDAY "), FRIDAY (5, "FRIDAY"), SATURDAY (6, "SATURDAY") and SUNDAY (7, "SUNDAY"); WeekDayEnum(Integer code, String desc) { this.code = code; this.desc = desc; } private final Integer code; @EnumValue private final String desc; }Copy the code
Copy the code

Database:

CREATE TABLE 't_user' (' id' bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', 'name' varchar(50) DEFAULT 'COMMENT ',' age 'tinyint(3) unsigned DEFAULT NULL COMMENT' age ', 'rest_day' varchar(50) COMMENT 'rest ',' create_time 'TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP COMMENT' create time ', 'update_time' TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'update_time' 'deleted' tinyint(1) unsigned DEFAULT '0' COMMENT 'Deleted ', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;Copy the code

application.yml

server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/mysql? useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true username: root password: xpar driver-class-name: com.mysql.cj.jdbc.Driver mybatis: mapper-locations: classpath:mapper/**/*.xml configuration: map-underscore-to-camel-case: EnumTypeHandler default-enum type-handler: Mybatis enumerator; Org. Apache. Ibatis. Type. EnumOrdinalTypeHandler # to specify a custom enumeration type converter path - handlers - package: com.jt.mybatisenum.handler logging: level: com.jt: debugCopy the code

MyBatis-Plus for enumeration processing

Sometimes it just so happens that MyBatis-Plus is surprisingly similar to us. Since 3.1.0, you can configure the default enumeration to omit the scan general enumeration configuration default enumeration configuration if you do not need native enumeration

  • Upgrade instructions:

The following version changes the native default behavior. When upgrading, set the default enumeration to EnumOrdinalTypeHandler

  • Affected Users:

Use native enumerations in entities

  • Other notes:

Caches that use annotation enumerations can be pre-registered when configuring enumeration package scans

This article is part of the “Gold Nuggets For Free!” Event, click to view details of the event