|
2 | 2 | The library will generate a variety of INSERT statements:
|
3 | 3 |
|
4 | 4 | 1. An insert for a single record
|
5 |
| -2. An insert for a batch of records |
6 |
| -3. An insert with a select statement |
| 5 | +1. An insert for multiple records with a single statement |
| 6 | +1. An insert for multiple records with a JDBC batch |
| 7 | +2. An insert with a select statement |
7 | 8 |
|
8 | 9 | ## Single Record Insert
|
9 | 10 | A single record insert is a statement that inserts a single record into a table. This statement is configured differently than other statements in the library so that MyBatis' support for generated keys will work properly. To use the statement, you must first create an object that will map to the database row, then map object attributes to fields in the database. For example:
|
@@ -92,6 +93,95 @@ MyBatis supports returning generated values from a single record insert, or a ba
|
92 | 93 |
|
93 | 94 | The important thing is that the `keyProperty` is set correctly. It should always be in the form `record.<attribute>` where `<attribute>` is the attribute of the record class that should be updated with the generated value.
|
94 | 95 |
|
| 96 | +## Multiple Row Insert Support |
| 97 | +A multiple row insert is a single insert statement that inserts multiple rows into a table. This can be a convenient way to insert a few rows into a table, but it has some limitations: |
| 98 | + |
| 99 | +1. Since it is a single SQL statement, you could generate quite a lot of prepared statement parameters. For example, suppose you wanted to insert 1000 records into a table, and each record had 5 fields. With a multiple row insert you would generate a SQL statement with 5000 parameters. There are limits to the number of parameters allowed in a JDBC prepared statement - and this kind of insert could easily exceed those limits. If you want to insert a large number of records, you should probably use a JDBC batch insert instead (see below) |
| 100 | +1. The performance of a giant insert statement may be less than you expect. If you have a large number of records to insert, it will almost always be more efficient to use a JDBC batch insert (see below). With a batch insert, the JDBC driver can do some optimization that is not possible with a single large statement |
| 101 | +1. Retrieving generated values with multiple row inserts can be a challenge. MyBatis currently has some limitations related to retrieving generated keys in multiple row inserts that require special considerations (see below) |
| 102 | + |
| 103 | +Nevertheless, there are use cases for a multiple row insert - especially when you just want to insert a few records in a table and don't need to retrieve generated keys. In those situations, a multiple row insert will be an easy solution. |
| 104 | + |
| 105 | +A multiple row insert statement looks like this: |
| 106 | + |
| 107 | +```java |
| 108 | + try (SqlSession session = sqlSessionFactory.openSession()) { |
| 109 | + GeneratedAlwaysAnnotatedMapper mapper = session.getMapper(GeneratedAlwaysAnnotatedMapper.class); |
| 110 | + List<GeneratedAlwaysRecord> records = getRecordsToInsert(); // not shown |
| 111 | + |
| 112 | + MultiRowInsertStatementProvider<GeneratedAlwaysRecord> multiRowInsert = insertMultiple(records) |
| 113 | + .into(generatedAlways) |
| 114 | + .map(id).toProperty("id") |
| 115 | + .map(firstName).toProperty("firstName") |
| 116 | + .map(lastName).toProperty("lastName") |
| 117 | + .build() |
| 118 | + .render(RenderingStrategy.MYBATIS3); |
| 119 | + |
| 120 | + int rows = mapper.insertMultiple(multiRowInsert); |
| 121 | + } |
| 122 | +``` |
| 123 | + |
| 124 | +### Annotated Mapper for Multiple Row Insert Statements |
| 125 | +The MultiRowInsertStatementProvider object can be used as a parameter to a MyBatis mapper method directly. If you |
| 126 | +are using an annotated mapper, the insert method should look like this: |
| 127 | + |
| 128 | +```java |
| 129 | +import org.apache.ibatis.annotations.InsertProvider; |
| 130 | +import org.mybatis.dynamic.sql.insert.render.MultiRowInsertStatementProvider; |
| 131 | +import org.mybatis.dynamic.sql.util.SqlProviderAdapter; |
| 132 | + |
| 133 | +... |
| 134 | + @InsertProvider(type=SqlProviderAdapter.class, method="insertMultiple") |
| 135 | + int insertMultiple(MultiRowInsertStatementProvider<SimpleTableRecord> insertStatement); |
| 136 | +... |
| 137 | + |
| 138 | +``` |
| 139 | + |
| 140 | +### XML Mapper for Multiple Row Insert Statements |
| 141 | +We do not recommend using an XML mapper for insert statements, but if you want to do so the MultiRowInsertStatementProvider object can be used as a parameter to a MyBatis mapper method directly. |
| 142 | + |
| 143 | +If you are using an XML mapper, the insert method should look like this in the Java interface: |
| 144 | + |
| 145 | +```java |
| 146 | +import org.mybatis.dynamic.sql.insert.render.MultiInsertStatementProvider; |
| 147 | + |
| 148 | +... |
| 149 | + int insertMultiple(MultiRowInsertStatementProvider<SimpleTableRecord> insertStatement); |
| 150 | +... |
| 151 | + |
| 152 | +``` |
| 153 | + |
| 154 | +The XML element should look like this: |
| 155 | + |
| 156 | +```xml |
| 157 | + <insert id="insertMultiple"> |
| 158 | + ${insertStatement} |
| 159 | + </insert> |
| 160 | +``` |
| 161 | + |
| 162 | +### Generated Values |
| 163 | +MyBatis supports returning generated values from a multiple row insert statement with some limitations. The main limitation is that MyBatis does not support nested lists in parameter objects. Unfortunately, the `MultiRowInsertStatementProvider` relies on a nested List. It is likely this limitation in MyBatis will be removed at some point in the future, so stay tuned. |
| 164 | + |
| 165 | +Nevertheless, you can configure a mapper that will work with the `MultiRowInsertStatementProvider` as created by this library. The main idea is to decompose the statement from the parameter map and send them as separate parameters to the MyBatis mapper. For example: |
| 166 | + |
| 167 | +```java |
| 168 | +... |
| 169 | + @Insert({ |
| 170 | + "${insertStatement}" |
| 171 | + }) |
| 172 | + @Options(useGeneratedKeys=true, keyProperty="records.fullName") |
| 173 | + int insertMultipleWithGeneratedKeys(@Param("insertStatement") String statement, @Param("records") List<GeneratedAlwaysRecord> records); |
| 174 | + |
| 175 | + default int insertMultipleWithGeneratedKeys(MultiRowInsertStatementProvider<GeneratedAlwaysRecord> multiInsert) { |
| 176 | + return insertMultipleWithGeneratedKeys(multiInsert.getInsertStatement(), multiInsert.getRecords()); |
| 177 | + } |
| 178 | +... |
| 179 | +``` |
| 180 | + |
| 181 | +The first method above shows the actual MyBatis mapper method. Note the use of the `@Options` annotation to specify that we expect generated values. Further note that the `keyProperty` is set to `records.fullName` - in this case, `fullName` is a property of the objects in the `records` List. |
| 182 | + |
| 183 | +The second method above decomposes the `MultiRowInsertStatementProvider` and calls the first method. |
| 184 | + |
95 | 185 | ## Batch Insert Support
|
96 | 186 | A batch insert is a collection of statements that can be used to execute a JDBC batch. A batch is the preferred method of doing bulk inserts with JDBC. The basic idea is that you configure the connection for a batch insert, then execute the same statement multiple times, with different values for each inserted record. MyBatis has a nice abstraction of JDBC batches that works well with statements generated from this library. A batch insert looks like this:
|
97 | 187 |
|
|
0 commit comments