DBUtils source code analysis, dbutils source code

Source: Internet
Author: User

DBUtils source code analysis, dbutils source code

In fact, in this article, I only analyzed the operation process of dbutis query.

As for why the class should be designed in this way, the design patterns and other advanced knowledge points should be discussed in the next section.

First, let's take a look at how the simplest DBUtils works.

There is a table in the database, student, which contains three attribute names, student ID, birth date (xm, xh, birth), the first two of which are vchar and birth are date;

package dbutils;import model.Student;import org.apache.commons.dbutils.QueryRunner;import org.apache.commons.dbutils.handlers.BeanHandler;import org.apache.commons.dbutils.ResultSetHandler;import org.junit.Test;import java.sql.SQLException;public class BeanExample {    @Test    public void testBean() {            QueryRunner qr = new QueryRunner(new MyDBSource());        String sql = "select * from student where xh=?";        Object params[] = { "02" };        Student s=null;        try {            ResultSetHandler<Student> rsh=new BeanHandler<>(Student.class);            s =  qr.query(sql,rsh,params);        } catch (SQLException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        System.out.println(s.getXm());    }}


MyDBSource is a tool that provides data sources.
public class MyDBSource implements DataSource {    private static String driverClassName = "com.mysql.jdbc.Driver";    private static String url = "jdbc:mysql://localhost:3306/webexample";    private static String userName = "root";    private static String passWord = "root";        @Override    public Connection getConnection() throws SQLException {        try {            Class.forName(driverClassName);        } catch (ClassNotFoundException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        return DriverManager.getConnection(url, userName, passWord);    }    //....}
Let's look at the BeanHandler's interior.
    //BeanHandler.java    public BeanHandler(Class<T> type) {        this(type, ArrayHandler.ROW_PROCESSOR);    }    public BeanHandler(Class<T> type, RowProcessor convert) {        this.type = type;        this.convert = convert;    }    //ArrayHandler.java    public class ArrayHandler implements ResultSetHandler<Object[]> {         static final RowProcessor ROW_PROCESSOR = new BasicRowProcessor();          //....    }    //BasicRowProcessor.java    public class BasicRowProcessor implements RowProcessor {      private static final BeanProcessor defaultConvert = new BeanProcessor();               public BasicRowProcessor() {             this(defaultConvert);          }      //...    }


OK. We can see that the convert in BeanHandler is the BeanProcessor type.

Next we will be playing a major role.
    s =  qr.query(sql,rsh,params);

Let's look at the sequence chart.



1.1 prepareStatement (conn, SQL );
       protected PreparedStatement prepareStatement(Connection conn, String sql)            throws SQLException {        return conn.prepareStatement(sql);    }
Is to generate prepareStatement
1.2 fillStatement (stmt, params)
You should know the name. fillStatement is a parameter.
The core code is as follows:
     for (int i = 0; i < params.length; i++) {            if (params[i] != null) {                stmt.setObject(i + 1, params[i]);            }        //...     }
Of course, there is another piece of fillStatement on the core code, that is, check whether the number of question marks in SQL is equal to the length of params.
1.3 handle (rs)
     BeanHandler.java     public T handle(ResultSet rs) throws SQLException {        return rs.next() ? this.convert.toBean(rs, this.type) : null;      }
When we first analyzed the BeanHandler constructor, we knew that convert was BeanProcessor.
1.3.1 toBean (rs, this. type)
    public <T> T toBean(ResultSet rs, Class<T> type) throws SQLException {        PropertyDescriptor[] props = this.propertyDescriptors(type);        ResultSetMetaData rsmd = rs.getMetaData();        int[] columnToProperty = this.mapColumnsToProperties(rsmd, props);        return this.createBean(rs, type, props, columnToProperty);    }
1.3.1.1 propertyDescriptors (type)
This is the property of the type (Student. class in the Code) obtained using Introspector)
1.3.1.2 mapColumnsToProperties (rsmd, props)
This step is troublesome. Why bother.
In the database, a table contains fields, which are now stored in ResultSetMetaData.
In our bean, there is a property, which is now stored in the props array.

ColumnToProperty contains the correspondence between fields and attributes.
For example, columnToProperty [3] = 4 means the Third Field in ResultSetMetaData corresponds to the fourth attribute in the bean's PropertyDescriptor.

1.3.1.3 createBean (rs, type, props, columnToProperty)
// Slightly modify the source code. // It does not affect the core idea. private <T> T createBean (ResultSet rs, Class <T> type, PropertyDescriptor [] props, int [] columnToProperty) throws SQLException {T bean = this. newInstance (type); for (int I = 1; I <columnToProperty. length; I ++) {PropertyDescriptor prop = props [columnToProperty [I]; Class <?> PropType = prop. getPropertyType (); Object value = null; if (propType! = Null) value = this. processColumn (rs, I, propType); this. callSetter (bean, prop, value);} return bean ;}
In createBean
This. processColumn (rs, I, propType)
Is to obtain the value, so we already know the resultset, the serial number of this value in the resultset, and the value type. How can we get it?
I will not post the code. Let's look at the source code by yourself. We will be able to see the internal logic in five seconds.

1.3.1.3.1 callSetter (bean, prop, value)
The core here is the following code.
                // Don't call setter if the value object isn't the right type            if (this.isCompatibleType(value, params[0])) {                setter.invoke(target, new Object[]{value});            } else {              throw new SQLException(                  "Cannot set " + prop.getName() + ": incompatible types, cannot convert "                  + value.getClass().getName() + " to " + params[0].getName());                  // value cannot be null here because isCompatibleType allows null            }


If the value is a String and params is a double, an exception is thrown.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.