LindormTable es compatible con el protocolo MySQL, por lo que puede usar el framework de mapeo objeto-relacional (ORM) MyBatis para construir aplicaciones en Java. MyBatis separa el código SQL del código de la aplicación y le permite definir la lógica de acceso a datos en interfaces de mapeo. De este modo, la lógica de negocio queda libre de instrucciones SQL incrustadas.
Al finalizar este tutorial, habrá logrado lo siguiente:
Agregó las dependencias de MyBatis y del controlador JDBC de MySQL a un proyecto de Maven.
Configuró
mybatis-config.xmlpara conectarse a LindormTable.Definió una interfaz de mapeo con operaciones de creación, lectura, upsert y eliminación.
Ejecutó una demostración funcional contra LindormTable.
Requisitos previos
Antes de empezar, asegúrese de contar con lo siguiente:
La función de compatibilidad con MySQL habilitada en su instancia de LindormTable. Para más información, consulte Habilitar la función de compatibilidad con MySQL.
JDK 1.8 o una versión posterior instalada.
Su dirección IP cliente agregada a la lista de permitidos de su instancia de Lindorm. Para más información, consulte Configurar listas de permitidos.
Configuración del proyecto
Paso 1: Agregar las dependencias
En su proyecto de Maven, agregue a continuación las dependencias dentro del bloque dependencies del archivo pom.xml:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.14</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.3.0</version>
</dependency>
Paso 2: Configurar la conexión
En la carpeta resources, cree el archivo mybatis-config.xml con los parámetros de conexión para LindormTable:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://<MySQL-compatible endpoint>:33060/<database>?sslMode=disabled&allowPublicKeyRetrieval=true&useServerPrepStmts=true&useLocalSessionState=true&rewriteBatchedStatements=true&cachePrepStmts=true&prepStmtCacheSize=100&prepStmtCacheSqlLimit=50000000"/>
<property name="username" value="<username>"/>
<property name="password" value="<password>"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="org.example.UserMapper"/>
</mappers>
</configuration>
Reemplace los siguientes marcadores de posición:
|
Marcador de posición |
Descripción |
|
|
El endpoint compatible con MySQL de su instancia. Para obtener este valor, consulte View endpoints. |
|
|
El nombre de la base de datos a la que se conectará. Si se omite, el cliente se conecta a la base de datos predeterminada. |
|
|
El nombre de usuario de la base de datos. |
|
|
La contraseña de la base de datos. Para restablecerla, consulte Change a user password. |
Selección del endpoint adecuado
|
Tipo de acceso |
Endpoint recomendado |
|
Desde una instancia de Elastic Compute Service (ECS) en la misma virtual private cloud (VPC) |
Dirección VPC del endpoint compatible con MySQL |
|
Desde Internet |
Dirección pública del endpoint compatible con MySQL |
Si su aplicación se ejecuta en una instancia de ECS, use el endpoint de VPC para mejorar la seguridad y reducir la latencia. Para conectarse por Internet, primero habilite el endpoint público: en la consola, vaya a Database Connection > Wide Table Engine y haga clic en Enable Public Endpoint.
Para conocer los detalles sobre los parámetros de la cadena de conexión y cómo mejoran el rendimiento, consulte Connection configuration.
Paso 3: Definir el modelo de datos
Cree una clase User para representar las filas de la tabla de demostración:
package org.example;
import java.nio.charset.StandardCharsets;
import java.sql.Date;
import java.sql.Timestamp;
public class User {
private int userId;
private String userName;
private double height;
private long score;
private Timestamp createTime;
private Date birthday;
private byte[] digest;
public User(int userId, String userName, double height, long score,
Timestamp createTime, Date birthday, byte[] digest) {
this.userId = userId;
this.userName = userName;
this.height = height;
this.score = score;
this.createTime = createTime;
this.birthday = birthday;
this.digest = digest;
}
public int getUserId() { return userId; }
public void setUserId(int userId) { this.userId = userId; }
public String getUserName() { return userName; }
public void setUserName(String userName) { this.userName = userName; }
public double getHeight() { return height; }
public void setHeight(double height) { this.height = height; }
public long getScore() { return score; }
public void setScore(long score) { this.score = score; }
public Timestamp getCreateTime() { return createTime; }
public void setCreateTime(Timestamp createTime) { this.createTime = createTime; }
public Date getBirthday() { return birthday; }
public void setBirthday(Date birthday) { this.birthday = birthday; }
public byte[] getDigest() { return digest; }
public void setDigest(byte[] digest) { this.digest = digest; }
@Override
public String toString() {
return "User{" + "userId=" + userId + ", userName='" + userName + '\'' +
", height=" + height + ", score=" + score + ", createTime=" + createTime +
", birthday=" + birthday + ", digest=" + new String(digest, StandardCharsets.UTF_8) + '}';
}
}
Paso 4: Crear el mapeador
Cree una interfaz UserMapper. Cada método lleva una anotación con la instrucción SQL que se ejecuta contra LindormTable:
package org.example;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
public interface UserMapper {
@Update("create table if not exists demo_user(`id` INT, `name` VARCHAR, `height` DOUBLE, `score` BIGINT, `createtime` TIMESTAMP, `birthday` DATE, digest VARBINARY, primary key(id))")
void createUserTable();
@Update("drop table if exists demo_user")
void dropUserTable();
@Insert("upsert into demo_user(`id`,`name`,`height`,`score`,`createtime`,`birthday`,`digest`) values(#{userId},#{userName},#{height},#{score},#{createTime},#{birthday},#{digest})")
int upsertUser(User user);
@Delete("delete from demo_user where `id` = #{userId}")
int deleteUser(@Param("userId") int userId);
@Select("select * from demo_user where `id` = #{userId}")
User selectOneUser(@Param("userId") int userId);
@Select("select * from demo_user")
List<User> selectAllUser();
}
Todas las operaciones de escritura usan upsert en lugar de insert. Esta es la sintaxis recomendada en LindormTable para insertar o actualizar filas con una sola instrucción.
Paso 5: Escribir el código de la aplicación
Cargue la configuración, abra una SqlSession y ejecute las operaciones CRUD mediante el mapeador:
package org.example;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.sql.Date;
import java.sql.Timestamp;
public class MybatisDemo {
public static void main(String[] args) throws Exception {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
// Create the table
mapper.createUserTable();
// Verify the table is empty
System.out.println(mapper.selectAllUser());
// Insert two users
User user1 = new User(1, "zhangsan", 1.8, 100,
new Timestamp(System.currentTimeMillis()),
Date.valueOf("1995-03-02"),
"hello".getBytes(StandardCharsets.UTF_8));
User user2 = new User(2, "lisi", 1.7, 90,
new Timestamp(System.currentTimeMillis()),
Date.valueOf("1996-08-02"),
"world".getBytes(StandardCharsets.UTF_8));
mapper.upsertUser(user1);
mapper.upsertUser(user2);
// Query all users and a single user
System.out.println(mapper.selectAllUser());
System.out.println(mapper.selectOneUser(1));
// Delete user1 and verify
mapper.deleteUser(1);
System.out.println(mapper.selectAllUser());
// Update user2's score using upsert and verify
user2.setScore(99);
mapper.upsertUser(user2);
System.out.println(mapper.selectAllUser());
// Clean up
mapper.dropUserTable();
}
}
}
Ejemplo completo
Descargue el proyecto de ejemplo completo: mybatis-demo.zip.
Tras una ejecución exitosa, la salida luce de la siguiente manera:
[User{userId=1, userName='zhangsan', height=1.8, score=100, createTime=2023-12-02 09:39:17.63, birthday=1995-03-02, digest=hello}, User{userId=2, userName='lisi', height=1.7, score=90, createTime=2023-12-02 09:39:17.63, birthday=1996-08-02, digest=world}]
User{userId=1, userName='zhangsan', height=1.8, score=100, createTime=2023-12-02 09:39:17.63, birthday=1995-03-02, digest=hello}
[User{userId=2, userName='lisi', height=1.7, score=90, createTime=2023-12-02 09:39:17.63, birthday=1996-08-02, digest=world}]
[User{userId=2, userName='lisi', height=1.7, score=99, createTime=2023-12-02 09:39:17.63, birthday=1996-08-02, digest=world}]
Preguntas frecuentes
¿Por qué selectAllUser() genera el error "ExecutionPlaceholder cannot be cast to java.util.List"?
El error completo es el siguiente:
### Cause: java.lang.ClassCastException: class org.apache.ibatis.executor.ExecutionPlaceholder cannot be cast to class java.util.List
Los objetos SqlSession y Mapper de MyBatis no son seguros para subprocesos. Este error ocurre cuando varios hilos acceden al mismo SqlSession o Mapper de forma simultánea. Asegúrese de que cada hilo cree su propio SqlSession y obtenga su propio mapeador a partir de él.
¿Cuál es la diferencia entre los marcadores de posición #{} y ${}?
|
** |
** |
|
|
Implementación |
Vinculación de parámetros precompilados mediante |
Reemplazo directo de cadenas |
|
Riesgo de inyección SQL |
Ninguna |
Sí |
|
Rendimiento |
Alto: el plan de ejecución se reutiliza |
Bajo: cada instrucción se analiza de nuevo |
|
Cuándo usarlo |
Al vincular valores dinámicos, como las condiciones |
Al insertar fragmentos SQL, como nombres de tablas o columnas |
Use #{} para todos los valores de parámetros. Reserve ${} para estructuras SQL dinámicas donde no sea posible la vinculación parametrizada.
#{} solo genera una consulta verdaderamente parametrizada si se establece useServerPrepStmts=true en la cadena de conexión. Sin este parámetro, el controlador JDBC de MySQL reescribe la instrucción como una cadena literal durante la ejecución y omite la precompilación. Para más información, consulte Connection configuration.
Pasos siguientes
Documentación de MyBatis: sintaxis XML del mapeador, SQL dinámico y configuración avanzada.
Conexión mediante JDBC de Java: parámetros de la cadena de conexión y ajuste de rendimiento para LindormTable.