Know yourself and know your enemy: persistent evolution

Time:2020-12-1

introduction

When we talk about the word “persistence”, we must be familiar with the word “persistence”.

In the process of persistence, there are two giants that attract the attention of developersHibernateAndMyBatisMany developers often compare the two. goGoogleOn, are similar to the two articles contrast each other.

Know yourself and know your enemy: persistent evolution

HibernateAndMyBatisIt’s likejavaandphpSimilarly, there seems to be a fight between the two sides.

Although I am using itHibernateBut I don’t deny itMyBatis, both are excellent, but everything is business priority.

After learning Mr. Pan’s “springboot + angular introductory example tutorial”, I also thought of the most originalJDBC

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

Persistence

JDBC in ancient times

JDBCJava Database Connectivity, abbreviated asJDBC。 yesJavaThe application program interface (API) is used to regulate how the client program accesses the database, and provides methods such as querying and updating the data in the database.JDBCIt is oriented to relational database.

EveryoneJavaProgrammers may all have experiencedJDBCFear of domination.

Here I amJavaIt was written in the lab classJDBCCode, the implementation of the function is very simple, is to put aStudentObject is saved to thestudentIn the table.

/**
 *Persistent student entity
 */
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 connection
        Connection connection = DriverManager.getConnection(url, "root", "root");
        //Get statement
        Statement statement = connection.createStatement();
        //Generate SQL statement
        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());
    } finally {
        statement.close();
        connection.close();
    }
}

The core function is actually one line:statement.executeUpdate(SQL)I just want to implement oneINSERTStatement to ensure data persistence.

But in theJDBCBut you need to implement loadingMySQLDrive, getConnection, getStatementCan be executedSQLAfter execution, you need to release resources manually, which is not a problem.

Programmers hate to write repetitive code, just like I feel it is boring to transplant duplicate code from huasoft platform to test platform, so these “template” code needs to be encapsulated.

Encapsulation tool class

We are all ordinary people. What we can think of must have been thought of for a long time.

SpringPackagedJDBC, providesJdbcTemplate

Another famous one isApacheEncapsulatedDBUtils

UsedJdbcTemplateAfter that, we don’t need to write a templateConnectionStatementtry ... catch ... finallyAnd so on. TheJdbcTemplateQuery the teacher table. The code length is as follows:

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

    /*Defines the object that implements the rowcallbackhandler interface*/
    RowCallbackHandler rowCallbackHandler = new RowCallbackHandler() {
        /**
         *This method is used to execute jdbcTemplate.query After the callback, each line of data callback once. For example, if there are two rows of data in the teacher table, call back this method twice.
         *
         *@ param resultset query results, one line at a time
         *When an error occurs in the @ throws sqlexception 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*/
            teacher.setId(resultSet.getLong("id"));
            /*Get the field name and convert it to string type*/
            teacher.setName(resultSet.getString("name"));
            /*Get the field sex and convert it to boolean type*/
            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";

    /*Use query to query, and the result of the query is called rowCallbackHandler.processRow The () method is passed to the rowcallbackhandler object*/
    jdbcTemplate.query(query, rowCallbackHandler);
    return teachers;
}

Thinking: since it can be passedResultSetGet the results here, whySpringEncapsulatedqueryMethod does not return directlyResultSetWhat about designing such a callback object?

Tips,JdbcTemplateThe core source code of the query is as follows:

@Override
@Nullable
public T doInStatement(Statement stmt) throws SQLException {
    ResultSet rs = null;
    try {
        rs = stmt.executeQuery(sql);
        return rse.extractData(rs);
    }
    finally {
        JdbcUtils.closeResultSet(rs);
    }
}

ResultSetIt’s annoying to use, isn’t it? You need to manually get the field and set it into the object,JdbcTemplateIt improves the development efficiency, but the improvement is not obvious. Can it be simpler?

ORM

In order to avoid writing a large number of such business independent code, theORMThought.

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

ORM: object relation mapping. By associating objects with data tables, we don’t need to pay attention to the redundant code of uncorrelated business, namely operation data table.

Semi automatic ORM

Semi automaticORMFrames are hotMyBatis

I simply went to learn the followingMyBatisAfter all, there must be a reason for so many companies to use it. If they are good enough, they can also consider using it. But the results were somewhat disappointing.

Open the official website to learn. This should be considered as the most humble official website of the famous open source framework I have ever seen. The content in it is not detailed.

Know yourself and know your enemy: persistent evolution

The examples on the official website are not detailed enough. I have read many moreMyBatisTo learn.

Open the configuration of database field underline to object named hump.

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

Or the classic relationship among teachers, classes and students

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’sCRUDSingle table 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);
}

Associated 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();
}

Used in associationStudentMapperSubquery:

@Mapper
public interface StudentMapper {

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

I’ve been learning for a whole night. Although I haven’t learned the advanced features like L2 cache, I’m still learningMyBatisIt can be regarded as another general understanding.

Business is the number one, and all technologies serve the business. Programmers should pay attention to business and practical problems. I don’t like to write themSQLOf course,SQLShould beDBAGo to professional study and optimize,MyBatisIt looks more like givingDBAThe same frame is used.

Fully automated ORM

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

Of course, the simpler the brick is, the better it isSQLHibernateWalk up.

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

It’s completely object-based and more business focused.

How to choose?

Many people are “you see Alipay.”MyBatisI’ll use it, tooMyBatis”。

This isStackOverflowThe last ten years ago about the comparison of the two topics: https://stackoverflow.com/questions/1984548/hibernate-vs-ibatis

Know yourself and know your enemy: persistent evolution

The final results are as follows:

iBatisandHibernateIt’s a completely different thing(iBatisyesMyBatisThe predecessor of.

If you’re object centric, thenHibernateBetter; if it’s database centric, theniBatisBetter.

If you design a system architecture that doesn’t require high concurrency,HibernateMost appropriately, the object model makes the code very concise, but at a high cost.

If you take over a legacy database and need to write complexSQLInquiry, thatiBatisMore appropriate.

To sum up, performance issues are:HibernateConvenient, but there will be performance loss;MyBatisIt has performance advantages.

summary

All saidMyBatisIt is suitable for high concurrency, but what about high concurrencyMyBatisCan we cover it?

Business is the boss. If we really encounter high concurrency requirements, it is time for us to improve.