JFinal学习--06操作数据库

在项目中,我们会需要使用到数据库,那么JFinal中是如何使用数据库的呢?

要使用数据库,我们首先需要建立数据库连接,JFinal给我们提供了两种现成的JDBC连接池,分别是C3p0 和 Druid,对应的相应的类是 C3p0Plugin 和 DruidPlugin,这两个类都实现了IDataSourceProvider接口,接口中定义了 getDataSource() 获取数据源的方法。

那么JFinal是如何通过连接池类,来操作数据库的呢?

这里,就要引入插件的概念–Plugin。

在JFinal中,插件会继承IPlugin接口,其中有 start() 和 stop() 两个方法。C3p0Plugin 和 DruidPlugin 也都实现了这个接口。具体如下:

这里写图片描述

其中,ActiveRecordPlugin就是进行数据库映射、配置的类。

下面,是操作数据库的流程,这里以保存用户为例:

1.首先建立数据库

CREATE DATABASE  IF NOT EXISTS `db_jfinal`
USE `db_jfinal`;
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

2.创建Model

public class User extends Model<User>{
    public static final User dao = new User();
}

3.在配置类中添加代码:

    @Override
    public void configPlugin(Plugins me) {
        C3p0Plugin cp = new C3p0Plugin("jdbc:mysql://localhost:3306/db_jfinal",
                "root", "admin");
        me.add(cp);
        ActiveRecordPlugin arp = new ActiveRecordPlugin(cp);
        me.add(arp);
        arp.addMapping("t_user", User.class);
    }

4.在Controller中执行保存用户操作

new User().set("name", "zorro").save();

在Jfinal中操作数据库就如上面这么简单,接下来,我们来看下具体是如何实现数据库保存的:

1.首先,在过滤器 JFinalFilter中的init方法中,静态变量jfinal会执行init方法,在这个方法中,会将配置类中的设置的插件取出,并启动。

com.jfinal.core.Config类中获取并启动插件:

static void configJFinal(JFinalConfig jfinalConfig) {
        jfinalConfig.configConstant(constants);             initLogFactory();
        jfinalConfig.configRoute(routes);
        jfinalConfig.configPlugin(plugins);                 startPlugins(); // very important!!!
        jfinalConfig.configInterceptor(interceptors);
        jfinalConfig.configHandler(handlers);
    }

2.由于在配置类中配置了两个插件,一个是C3p0Plugin,一个是ActiveRecordPlugin。
我们先看下C3p0Plugin的start方法:

public boolean start() {
        if (isStarted)
            return true;

        dataSource = new ComboPooledDataSource();
        dataSource.setJdbcUrl(jdbcUrl);
        dataSource.setUser(user);
        dataSource.setPassword(password);
        try {dataSource.setDriverClass(driverClass);}
        catch (PropertyVetoException e) {dataSource = null; System.err.println("C3p0Plugin start error"); throw new RuntimeException(e);} 
        dataSource.setMaxPoolSize(maxPoolSize);
        dataSource.setMinPoolSize(minPoolSize);
        dataSource.setInitialPoolSize(initialPoolSize);
        dataSource.setMaxIdleTime(maxIdleTime);
        dataSource.setAcquireIncrement(acquireIncrement);

        isStarted = true;
        return true;
    }

看代码知道,C3p0的启动,主要是实例化了一个数据源 dataSource,并给数据源设置了一些属性。

3.在看ActiveRecordPlugin,由于我们在配置类中实例化ActiveRecordPlugin的时候,将C3p0Plugin的实例传给了它,相当于ActiveRecordPlugin持有了数据源。

4.ActiveRecordPlugin的start() 方法如下:

public boolean start() {
        if (isStarted) {
            return true;
        }
        if (configName == null) {
            configName = DbKit.MAIN_CONFIG_NAME;
        }
        if (dataSource == null && dataSourceProvider != null) {
            dataSource = dataSourceProvider.getDataSource();
        }
        if (dataSource == null) {
            throw new RuntimeException("ActiveRecord start error: ActiveRecordPlugin need DataSource or DataSourceProvider");
        }
        if (config == null) {
            config = new Config(configName, dataSource);
        }

        if (dialect != null) {
            config.dialect = dialect;
        }
        if (showSql != null) {
            config.showSql = showSql;
        }
        if (devMode != null) {
            config.devMode = devMode;
        }
        if (transactionLevel != null) {
            config.transactionLevel = transactionLevel;
        }
        if (containerFactory != null) {
            config.containerFactory = containerFactory;
        }
        if (cache != null) {
            config.cache = cache;
        }

        new TableBuilder().build(tableList, config);
        DbKit.addConfig(config);
        Db.init();
        isStarted = true;
        return true;
    }

这里会实例化一个com.jfinal.plugin.activerecord.Config类,该类将持有数据源dataSource,之后DbKit.addConfig(config),会将config实例赋值给DbKit类下的静态属性,这使用了单例模式,以后再要使用数据源来获取连接,就不需要再实例化了,只要DbKit.getConfig() 就可以。

再看上面的

new TableBuilder().build(tableList, config);

这个操作是实现数据库的映射,通过查询各个表,将表中各字段记录到Table类中。并将table 保存到TableMapping中。

void build(List<Table> tableList, Config config) {
        if (tableList.size() == 0) {
            return ;
        }

        Table temp = null;
        Connection conn = null;
        try {
            conn = config.dataSource.getConnection();
            TableMapping tableMapping = TableMapping.me();
            for (Table table : tableList) {
                temp = table;
                doBuild(table, conn, config);
                tableMapping.putTable(table);
                DbKit.addModelToConfigMapping(table.getModelClass(), config);
            }
        } catch (Exception e) {
            if (temp != null) {
                System.err.println("Can not create Table object, maybe the table " + temp.getName() + " is not exists.");
            }
            throw new ActiveRecordException(e);
        }
        finally {
            config.close(conn);
        }
    }

5.最后是保存数据。
实体类User 继承了com.jfinal.plugin.activerecord.Model类,这个Model类中,就包含的对数据库操作方法。

Model中有属性Map

public boolean save() {
        Config config = getConfig();
        Table table = getTable();

        StringBuilder sql = new StringBuilder();
        List<Object> paras = new ArrayList<Object>();
        config.dialect.forModelSave(table, attrs, sql, paras);
        // if (paras.size() == 0)   return false;   // The sql "insert into tableName() values()" works fine, so delete this line

        // --------
        Connection conn = null;
        PreparedStatement pst = null;
        int result = 0;
        try {
            conn = config.getConnection();
            if (config.dialect.isOracle())
                pst = conn.prepareStatement(sql.toString(), table.getPrimaryKey());
            else
                pst = conn.prepareStatement(sql.toString(), Statement.RETURN_GENERATED_KEYS);

            config.dialect.fillStatement(pst, paras);
            result = pst.executeUpdate();
            getGeneratedKey(pst, table, config);
            getModifyFlag().clear();
            return result >= 1;
        } catch (Exception e) {
            throw new ActiveRecordException(e);
        } finally {
            config.close(pst, conn);
        }
    }

仔细看下,其实就是普通的JDBC操作。至此,整个操作数据库的流程就完成了。

猜你喜欢

转载自blog.csdn.net/leoxyk/article/details/51027220