Know Your Own and Know Your Own: Persistent Evolution

Keywords: Database Mybatis JDBC Hibernate

Introduction

When it comes to the word "persistence", people who operate databases every day are certainly familiar with it.

In persistence, the two giants that have caught the attention of developers are Hibernate and MyBatis, and many developers often compare them.Google is a comparison of the two.

Hibernate and MyBatis, like java and php, seem to be fighting.

Although I'm an engineer using Hibernate, I don't deny that MyBatis is good at both, but everything is business priority.

Learned from Mr. Pan Introduction to SpringBoot+Angular Example Tutorial Then I think of the most original JDBC.

Today, we will talk about the evolution and comparison of persistent technology from ancient to present.

Persistence

Ancient JDBC

JDBC: Java Database Connectivity, short for JDBC.Is an application interface in the Java language that specifies how client programs access the database, providing methods such as querying and updating data in the database.JDBC is relational database oriented.

Every Java programmer may experience fear of being dominated by JDBC.

The following is the JDBC code that I wrote in my Java experiment. The simple function is to save a Student object to a student table in a database.

/**
 * Persistent Chemical Entities
 */
private static void persistStudent(Student student) {
    try {
        Class.forName("com.mysql.jdbc.Driver");
        // Database Connection Configuration
        String url = "jdbc:mysql://127.0.0.1:7777/java?characterEncoding=utf-8";
        // Get Connections
        Connection connection = DriverManager.getConnection(url, "root", "root");
        // Get statement
        Statement statement = connection.createStatement();
        // Automatic Generate SQL
        String SQL = student.toSQLString();
        // Execute Statement
        statement.executeUpdate(SQL);
    } catch (SQLException e) {
        System.out.println("ERROR: " + e.getMessage());
    } catch (ClassNotFoundException e) {
        System.out.println("ERROR: " + e.getMessage());
    }
}

The core function is one line: statement.executeUpdate(SQL), and I just want to execute an INSERT statement to ensure data persistence.

However, in JDBC, you need to load MySQL driver, get Connection, get Statement to execute SQL, and manually release resources after execution.

Programmers hate to write duplicate code as much as I find it boring to migrate duplicate code from China Software Platform to Test Platform, so these "template" codes need to be encapsulated.

Encapsulation Tool Class

We are all ordinary people, and it must have been thought of before.

Spring encapsulates JDBC and provides JdbcTemplate.

Another well-known is Apache-encapsulated DBUtils.

With JdbcTemplate, we no longer need to write template-style code such as Connection, Statement, try... Catch... Finally.The tutorial uses JdbcTemplate to query the teacher table, and the code is as long as this:

@GetMapping
public List<Teacher> getAll() {
    /* Initialize an array of variable sizes */
    List<Teacher> teachers = new ArrayList<>();

    /* Define an object that implements the RowCallbackHandler interface */
    RowCallbackHandler rowCallbackHandler = new RowCallbackHandler() {
        /**
         * This method is used to perform callbacks after jdbcTemplate.query, once per row of data.For example, if there are two rows of data in the Teacher table, the method is called back twice.
         *
         * @param resultSet Query results, one row at a time
         * @throws SQLException When an error occurs in the query, this exception will be thrown and will not be handled for the time being.
         */
        @Override
        public void processRow(ResultSet resultSet) throws SQLException {
            Teacher teacher = new Teacher();
            /* Get the field id and convert it to Long type to return */
            teacher.setId(resultSet.getLong("id"));
            /* Get the field name and convert it to String type to return */
            teacher.setName(resultSet.getString("name"));
            /* Get the field sex and convert it to Boolean type Return */
            teacher.setSex(resultSet.getBoolean("sex"));
            teacher.setUsername(resultSet.getString("username"));
            teacher.setEmail(resultSet.getString("email"));
            teacher.setCreateTime(resultSet.getLong("create_time"));
            teacher.setUpdateTime(resultSet.getLong("update_time"));
            
            /* Add the resulting teacher to the array to be returned */
            teachers.add(teacher);
        }
    };

    /* Define Query String */
    String query = "select id, name, sex, username, email, create_time, update_time from teacher";

    /* Query using query and pass the results of the query to the rowCallbackHandler object by calling the rowCallbackHandler.processRow() method */
    jdbcTemplate.query(query, rowCallbackHandler);
    return teachers;
}

ResultSet is annoying to use, isn't it?JdbcTemplate improves development efficiency by manually getting fields and setting them into objects, but the improvement is not obvious. Can it be easier?

ORM

To avoid writing a lot of this business-independent code, the ORM idea was designed.

teacher.setName(resultSet.getString("name"));
teacher.setSex(resultSet.getBoolean("sex"));
teacher.setUsername(resultSet.getString("username"));
teacher.setEmail(resultSet.getString("email"));

ORM: An object-relational mapping.Associating objects with data tables eliminates the need to focus on redundant code for such unrelated businesses, manipulating objects, that is, manipulating data tables.

Semi-automatic ORM

The semi-automated ORM framework is the hot MyBatis.

I simply learned the following MyBatis. After all, so many companies use it, they certainly make sense. If it's good enough, you can also consider using it.But the results were somewhat disappointing.

Open the official website to learn, this should be the most sour and famous open source framework I've ever seen, and its contents are not detailed.

The examples on the official website are not detailed enough, and I read many of MyBatis's blogs to learn about them.

Turn on the configuration of database field underscores to object named humps.

mybatis.configuration.map-underscore-to-camel-case=true

Or classic teacher-student relationships:

public class Teacher {

    private Long id;

    private String name;

    private Boolean sex;

    private String username;

    private String email;

    private Long createTime;

    private Long updateTime;
}

public class Klass {

    private Long id;

    private String name;

    private Teacher teacher;

    private List<Student> students;
}

public class Student {

    private Long id;

    private String name;
}

Teacher's CRUD form query:

@Mapper
public interface TeacherMapper {

    @Select("SELECT * FROM teacher")
    List<Teacher> getAll();

    @Select("SELECT * FROM teacher WHERE id = #{id}")
    Teacher get(Long id);

    @Select("SELECT * FROM teacher WHERE username = #{username}")
    Teacher findByUsername(String username);

    @Insert("INSERT INTO teacher(name, sex, username, email, create_time, update_time) VALUES(#{name}, #{sex}, #{username}, #{email}, #{createTime}, #{updateTime})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    void insert(Teacher teacher);

    @Update("UPDATE teacher SET name=#{name}, sex=#{sex}, email=#{email}, update_time=#{updateTime} WHERE id=#{id}")
    void update(Teacher teacher);

    @Delete("DELETE FROM teacher WHERE id=#{id}")
    void delete(Long id);
}

Association Query:

@Mapper
public interface KlassMapper {

    @Select("SELECT * FROM klass")
    @Results({
            @Result(column = "teacher_id", property = "teacher", one = @One(select = "club.yunzhi.mybatis.mapper.TeacherMapper.get")),
            @Result(column = "id", property = "students", many = @Many(select = "club.yunzhi.mybatis.mapper.StudentMapper.getAllByKlassId"))
    })
    List<Klass> getAll();
}

StudentMapper subquery used in association:

@Mapper
public interface StudentMapper {

    @Select("SELECT * FROM student WHERE klass_id=#{klassId}")
    List<Student> getAllByKlassId(Long klassId);
}

I've also been learning for one night. Although I haven't yet learned advanced features like Level 2 Cache, I know MyBatis as a whole.

Business is big, and all technology serves business.Programmers should focus on business and practical issues. I don't really like writing SQL. SQL should be learned and optimized by DBA. MyBatis looks more like a framework for DBA.

Fully automatic ORM

When a system is designed, the other work is to move bricks.

Of course, the easier it is to move bricks, the better. Without writing SQL, Hibernate starts.

public interface TeacherRepository extends CrudRepository<Teacher, Long> {
}

Fully object-based, more business-focused.

How to choose?

Many people are "You see Alipay uses MyBatis, so I use MyBatis too."

This was the topic that StackOverflow discussed a decade ago about comparing the two: https://stackoverflow.com/questions/1984548/hibernate-vs-ibatis

The final results of the discussion are as follows:

IBatis and Hibernate are completely different things (iBatis was the predecessor of MyBatis).

Hibernate is better if it's object-centric; iBatis is better if it's database-centric.

If you design your system architecture without high concurrency requirements, Hibernate is best suited, and the object model will make your code very simple but costly.

iBatis is more appropriate if you take over a legacy database and need to write complex SQL queries.

To summarize, there's a performance issue: Hibernate is convenient, but it can lose performance; MyBatis has a performance advantage.

summary

It is said that MyBatis is suitable for high concurrency, but can high concurrency be included by a MyBatis?

Business is big. If we really meet high concurrent demand, it is time for us to make progress.

Posted by ClanCC on Thu, 21 Nov 2019 12:14:01 -0800