In-depth understanding of the execution principle of @InsertProvider

1. First, the insert statement should be spliced, which contains input parameters and mapping fields with database table fields.

When executing the dynamic insert sql in the Provider class, the program will call the abstract class AbstractSQL to execute the two methods of splicing strings inside.

   public T INSERT_INTO(String tableName) {
        this.sql().statementType = AbstractSQL.SQLStatement.StatementType.INSERT;
        this.sql().tables.add(tableName);
        return this.getSelf();
    }

    public T VALUES(String columns, String values) {
        this.sql().columns.add(columns);
        this.sql().values.add(values);
        return this.getSelf();
    }

This abstract class has a private static class SQLStatement and a private static SalfAppendable class. There is a common static enumeration class in the SQLStatement class, which has one of its private constructors. The enumeration is designed to be a singleton mode, that is, the enumeration type will be instantiated by the JVM when the enumeration object is loaded. How many are defined in the enumeration class will be instantiated. In order to ensure a unique instance of each enumeration class element, the JVM will not allow external new, so the constructor will be designed as private to prevent users from generating instances , destroying uniqueness. The enumeration class contains four types of additions, deletions, and changes. The private static class SQLStatement has various keyword lists of SQL statements, and distinct is of boolean type, for example:

   List<String> sets = new ArrayList();
List<String> columns = new ArrayList();

The subclass ArrayList instantiates List, because List is an interface, so it can only rely on its "subclass" (here is the implementation class of List) to instantiate, and the object here is the object of List.

  private void sqlClause(AbstractSQL.SafeAppendable builder, String keyword, List<String> parts, String open, String close, String conjunction) {
            if(!parts.isEmpty()) {
                if(!builder.isEmpty()) {
                    builder.append("\n");
                }

                builder.append(keyword);
                builder.append(" ");
                builder.append(open);
                String last = "________";
                int i = 0;

                for(int n = parts.size(); i < n; ++i) {
                    String part = (String)parts.get(i);
                    if(i > 0 && !part.equals(") \nAND (") && !part.equals(") \nOR (") && !last.equals(") \nAND (") && !last.equals(") \nOR (")) {
                        builder.append(conjunction);
                    }

                    builder.append(part);
                    last = part;
                }

                builder.append(close);
            }

        }

The above function is a general SQL parsing function for additions, deletions, and changes. The following is the function to be called

  private String insertSQL(AbstractSQL.SafeAppendable builder) {
            this.sqlClause(builder, "INSERT INTO", this.tables, "", "", "");
            this.sqlClause(builder, "", this.columns, "(", ")", ", ");
            this.sqlClause(builder, "VALUES", this.values, "(", ")", ", ");
            return builder.toString();
        }

Use the following function to determine the function to be called by adding, deleting, checking, and modifying

public String sql(Appendable a) {
            AbstractSQL.SafeAppendable builder = new AbstractSQL.SafeAppendable(a);
            if(this.statementType == null) {
                return null;
            } else {
                String answer;
                switch(null.$SwitchMap$org$apache$ibatis$jdbc$AbstractSQL$SQLStatement$StatementType[this.statementType.ordinal()]) {
                case 1:
                    answer = this.deleteSQL(builder);
                    break;
                case 2:
                    answer = this.insertSQL(builder);
                    break;
                case 3:
                    answer = this.selectSQL(builder);
                    break;
                case 4:
                    answer = this.updateSQL(builder);
                    break;
                default:
                    answer = null;
                }

                return answer;
            }
        }
The private static SalfAppendable class is used to concatenate sql strings. There is a private Appendable object that cannot be changed.


private static class SafeAppendable {
        private final Appendable a;
        private boolean empty = true;

        public SafeAppendable(Appendable a) {
            this.a = a;
        }

        public AbstractSQL.SafeAppendable append(CharSequence s) {
            try {
                if(this.empty && s.length() > 0) {
                    this.empty = false;
                }

                this.a.append(s);
                return this;
            } catch (IOException var3) {
                throw new RuntimeException(var3);
            }
        }

        public boolean isEmpty() {
            return this.empty;
        }
    }



Then call the ProviderSqlSource class, then call the immutable class MappedStatement class, then call the BaseStatementHandler class, ---> PreparedStatementHandler, etc.

2. ProviderSqlSource implements the sqlSource interface, which represents reading the content of the relevant mapping statement from the annotation, and the sql it creates will be transmitted to the database.

Depending on the type of SQL statement, mybatis provides a variety of specific implementations of SqlSource:

1) StaticSqlSource: The final encapsulation of static SQL statements, and other types of SqlSource are ultimately delegated to StaticSqlSource.
2) RawSqlSource: The encapsulation of the original static SQL statement, the SQL statement has been determined at the time of loading, without dynamic tags such as , and ${} SQL splicing, which is faster than dynamic SQL statements because it does not require runtime parsing of SQL nodes.
3) DynamicSqlSource: The encapsulation of dynamic SQL statements. At runtime, the static SQL statement to be executed can only be generated after parameter processing, etc. tags or ${} SQL splicing.
4) ProviderSqlSource: When the SQL statement is obtained through the specified class and method (annotated with @XXXProvider), this class needs to be used, and it will call the corresponding method through reflection to obtain the SQL statement





Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324830465&siteId=291194637