JFinal学习--06操作数据库

来源:互联网 发布:php统计总访问量代码 编辑:程序博客网 时间:2024/06/05 19:08

在项目中,我们会需要使用到数据库,那么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操作。至此,整个操作数据库的流程就完成了。

2 0