Do you really understand ORM? Learn ORM through a simple example

What is ORM

ORM (Object-Relational Mapping) is a technology that maps object-oriented program data models to relational databases.

For example, the database table user, which has id, name, and age fields mapped to the Java entity class is the User class, which has id, name, and age attributes.

 
 

sql

Copy code

CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) COLLATE utf8mb4_general_ci DEFAULT NULL, `age` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

 
 

java

Copy code

@Entity @Table(name = "user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; private String name; private int age; // 省略setter和getter }

What is JPA

JPA (Java Persistence API) (Java Persistence Interface) is a standardized persistence framework provided by the Java platform to simplify the interaction between Java objects and databases.

JPA helps you hide the underlying database details. You only need to operate objects without writing complex SQL statements. JPA will automatically generate and execute corresponding SQL statements for you.

In fact, JPA has defined a series of annotations for me. It does not provide specific implementations, but only defines specifications. as follows:

Are the following annotations familiar?

 
 

java

Copy code

@Documented @Target(TYPE) @Retention(RUNTIME) public @interface Entity { String name() default ""; } public @interface OneToMany { Class targetEntity() default void.class; CascadeType[] cascade() default {}; FetchType fetch() default LAZY; String mappedBy() default ""; boolean orphanRemoval() default false; } @Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface Column { String name() default ""; boolean unique() default false; boolean nullable() default true; boolean insertable() default true; boolean updatable() default true; String columnDefinition() default ""; String table() default ""; int length() default 255; int precision() default 0; int scale() default 0; }

That is, JPA only defines interface specifications, and how to implement each manufacturer's own. The following is a commonly used framework based on JPA.

  • Hibernate
  • OpenJPA
  • Spring Data JPA

Encapsulate an ORM framework yourself

Let's encapsulate a simple ORM framework by yourself through a code example.

Introduce dependent packages, namely mysql-connector-java and javax.persistence-api

 
 

xml

Copy code

<dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> <dependency> <groupId>javax.persistence</groupId> <artifactId>javax.persistence-api</artifactId> <version>2.2</version> </dependency> </dependencies>


The following is JDBC to obtain the database connection

 
 

java

Copy code

import java.sql.Connection; import java.sql.DriverManager; public class ConnectionUtil { public static Connection getConnection() throws Exception { String url = "jdbc:mysql://localhost:3306/jdbc_orm?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false"; String user = "root"; String password = "123456"; return DriverManager.getConnection(url, user, password); } }


The specific ORM core code is implemented with Java reflection technology.

 
 

java

Copy code

import javax.persistence.Entity; import javax.persistence.Id; import java.lang.reflect.Field; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; public class OrmUtil { private final Connection connection; public OrmUtil(Connection connection) { this.connection = connection; } public <T> void save(T entity) throws Exception { // 获取实体对象的Class对象 Class<?> clazz = entity.getClass(); // 获取实体对象所对应的数据库表名 String tableName = getTableName(clazz); // 存储实体对象的列名和对应的值 List<String> columns = new ArrayList<>(); List<Object> values = new ArrayList<>(); // 获取实体对象的字段 Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { // 设置字段可访问 field.setAccessible(true); // 存储字段名 columns.add(field.getName()); // 存储字段值,由于是Object类型,需要强制类型转换 values.add(field.get(entity)); } // 构建SQL语句 StringBuilder sqlBuilder = new StringBuilder(); sqlBuilder.append("INSERT INTO ").append(tableName).append(" ("); for (int i = 0; i < columns.size(); i++) { sqlBuilder.append(columns.get(i)); if (i < columns.size() - 1) { sqlBuilder.append(", "); } } sqlBuilder.append(") VALUES ("); for (int i = 0; i < values.size(); i++) { sqlBuilder.append("?"); if (i < values.size() - 1) { sqlBuilder.append(", "); } } sqlBuilder.append(")"); String sql = sqlBuilder.toString(); // 打印SQL语句 System.out.println("执行新增语句;" + sql); // 执行SQL语句 try (PreparedStatement statement = connection.prepareStatement(sql)) { for (int i = 0; i < values.size(); i++) { // 设置参数,由于参数类型不确定,使用setObject方法 statement.setObject(i + 1, values.get(i)); } statement.executeUpdate(); } } public <T> void update(T entity) throws Exception { // 获取实体对象的Class对象 Class<?> clazz = entity.getClass(); // 获取实体对象所对应的数据库表名 String tableName = getTableName(clazz); // 存储实体对象的非主键列名和对应的值 List<String> columns = new ArrayList<>(); List<Object> values = new ArrayList<>(); // 存储主键值 Object idValue = null; // 获取实体对象的字段 Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { // 设置字段可访问 field.setAccessible(true); // 判断字段是否有@Id注解,若有,则将其值作为主键值存储 if (field.isAnnotationPresent(Id.class)) { idValue = field.get(entity); } else { // 若没有@Id注解,则将其列名和值存储 columns.add(field.getName()); values.add(field.get(entity)); } } // 构建SQL语句 StringBuilder sqlBuilder = new StringBuilder(); sqlBuilder.append("UPDATE ").append(tableName).append(" SET "); for (int i = 0; i < columns.size(); i++) { sqlBuilder.append(columns.get(i)).append(" = ?"); if (i < columns.size() - 1) { sqlBuilder.append(", "); } } sqlBuilder.append(" WHERE id = ?"); String sql = sqlBuilder.toString(); System.out.println("执行更新语句;" + sql); // 执行SQL语句 try (PreparedStatement statement = connection.prepareStatement(sql)) { for (int i = 0; i < values.size(); i++) { // 设置非主键列的参数值 statement.setObject(i + 1, values.get(i)); } // 设置主键参数值 statement.setObject(values.size() + 1, idValue); statement.executeUpdate(); } } public void delete(Class<?> clazz, Object id) throws Exception { // 获取实体对象所对应的数据库表名 String tableName = getTableName(clazz); // 构建SQL语句 String sql = "DELETE FROM " + tableName + " WHERE id = ?"; System.out.println("执行删除语句:" + sql); // 执行SQL语句 try (PreparedStatement statement = connection.prepareStatement(sql)) { // 设置参数值 statement.setObject(1, id); // 执行删除操作 statement.executeUpdate(); } } public <T> T findById(Class<T> clazz, Object id) throws Exception { // 获取实体对象所对应的数据库表名 String tableName = getTableName(clazz); // 构建SQL语句 String sql = "SELECT * FROM " + tableName + " WHERE id = ?"; System.out.println("执行查询语句;" + sql); // 执行SQL查询 try (PreparedStatement statement = connection.prepareStatement(sql)) { // 设置参数值 statement.setObject(1, id); // 执行查询操作并获取结果集 try (ResultSet resultSet = statement.executeQuery()) { // 如果有结果,则创建实体对象并设置字段值 if (resultSet.next()) { T entity = clazz.newInstance(); Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); // 根据字段名从结果集中获取对应的值,并设置到实体对象中 Object value = resultSet.getObject(field.getName()); field.set(entity, value); } return entity; } } } return null; } private String getTableName(Class<?> clazz) { // 判断类是否有@Entity注解 if (clazz.isAnnotationPresent(Entity.class)) { // 获取类上的@Entity注解对象 Entity entityAnnotation = clazz.getAnnotation(Entity.class); // 获取注解中的表名 String tableName = entityAnnotation.name(); // 如果注解中的表名为空,则将类名转换为小写作为表名 if (tableName.isEmpty()) { tableName = clazz.getSimpleName().toLowerCase(); } return tableName; } // 如果类没有@Entity注解,抛出异常 throw new IllegalArgumentException("类没有@Entity注解"); } }

This code is a simple ORM (Object Relational Mapping) tool class that can add, delete, modify, and query database tables by calling the save, update, delete, findById and other methods it provides.

This code mainly includes the following content:

  1. Obtain information such as attributes, methods, and annotations of classes through reflection;

  2. Add, delete, modify, check and other operations on the database are realized through PreparedStatement;

  3. Use the Java generic mechanism, such as using class names and primary key values ​​as method parameters in save, update, findById and other methods to achieve universal effects;

  4. The application of JPA annotations, such as parsing annotations such as @Id and @Entity, and obtaining annotation values.


Test addition, deletion, modification and check

 
 

java

Copy code

import java.sql.Connection; public class Test { public static void main(String[] args) { try { // 获取数据库连接 Connection connection = ConnectionUtil.getConnection(); // 创建一个实体管理器 OrmUtil ormUtil = new OrmUtil(connection); // 创建一个User对象 User user = new User(); user.setId(1); user.setName("张三"); user.setAge(28); // 保存User对象到数据库 ormUtil.save(user); // 修改User对象 user.setAge(30); ormUtil.update(user); // 根据id查询User对象 User foundUser = ormUtil.findById(User.class, 1); System.out.println("查询结果:"+foundUser); // 输出:"张三" // 删除User对象 ormUtil.delete(User.class, 1); } catch (Exception e) { e.printStackTrace(); } } }

Conclusion

The above is just the simplest addition, deletion, modification and query. The principles of actual ORM frameworks such as Hibernate are similar, but they provide more and richer interfaces for addition, deletion, modification and query. It is still necessary to deepen the use of reflection in Java.

Guess you like

Origin blog.csdn.net/Trouvailless/article/details/132277033