All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nutz.dao.impl.DaoSupport Maven / Gradle / Ivy

Go to download

Nutz, which is a collections of lightweight frameworks, each of them can be used independently

There is a newer version: 1.r.72
Show newest version
package org.nutz.dao.impl;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.HashSet;
import java.util.Set;

import javax.sql.DataSource;

import org.nutz.dao.ConnCallback;
import org.nutz.dao.DatabaseMeta;
import org.nutz.dao.SqlManager;
import org.nutz.dao.entity.EntityMaker;
import org.nutz.dao.impl.entity.AnnotationEntityMaker;
import org.nutz.dao.impl.sql.NutPojoMaker;
import org.nutz.dao.impl.sql.run.NutDaoExecutor;
import org.nutz.dao.impl.sql.run.NutDaoRunner;
import org.nutz.dao.jdbc.JdbcExpert;
import org.nutz.dao.jdbc.Jdbcs;
import org.nutz.dao.sql.DaoStatement;
import org.nutz.dao.sql.PojoMaker;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.sql.SqlContext;
import org.nutz.dao.util.Daos;
import org.nutz.lang.Strings;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.trans.Atom;
import org.nutz.trans.Trans;
import org.nutz.trans.Transaction;

/**
 * Dao 接口实现类的一些基础环境
 * 
 * @author zozoh([email protected])
 */
public class DaoSupport {

    private static final Log log = Logs.get();

    /**
     * 给子类使用的 Dao 的运行器,用来封装事务
     */
    protected DaoRunner runner;

    /**
     * 给子类使用的 Dao 语句执行器,用来具体运行某一条语句
     */
    protected DaoExecutor executor;

    /**
     * 给子类使用数据源
     */
    protected DataSource dataSource;

    /**
     * 给子类使用的数据特殊性的封装
     */
    protected JdbcExpert expert;

    /**
     * 给子类使用的 PojoStatementMaker 接口
     */
    protected PojoMaker pojoMaker;

    /**
     * 给子类使用的 Entity 获取对象
     */
    protected EntityHolder holder;

    /**
     * 数据库的描述
     */
    private DatabaseMeta meta;

    /**
     * SQL 管理接口实现类
     */
    private SqlManager sqlManager;
    
    protected int autoTransLevel = Connection.TRANSACTION_READ_COMMITTED;

    public DaoSupport() {
        this.runner = new NutDaoRunner();
        this.executor = new NutDaoExecutor();
    }

    /**
     * @return Sql 管理接口的实例
     */
    public SqlManager sqls() {
        return sqlManager;
    }

    /**
     * @return 当前连接的数据库的一些描述数据
     */
    public DatabaseMeta meta() {
        return meta;
    }

    /**
     * 设置一个新的 Sql 管理接口实例
     * 
     * @param sqls
     *            Sql 管理接口实例
     */
    public void setSqlManager(SqlManager sqls) {
        this.sqlManager = sqls;
        if (sqls != null) {
            int count = sqls.count();
            log.debug("SqlManager Sql count=" + count);
        }
    }

    /**
     * 设置一个新的 Dao 运行器
     * 
     * @param runner
     *            运行器对象
     */
    public void setRunner(DaoRunner runner) {
        this.runner = runner;
        if (runner instanceof NutDaoRunner) {
        	((NutDaoRunner)runner).setMeta(meta);
        }
    }

    /**
     * 设置一个新的 Dao 语句执行器
     * 
     * @param executor
     *            Dao 语句执行器对象
     */
    public void setExecutor(DaoExecutor executor) {
        this.executor = executor;
        if (executor instanceof NutDaoExecutor) {
        	((NutDaoExecutor)executor).setMeta(meta);
        	((NutDaoExecutor)executor).setExpert(expert);
        }
    }

    /**
     * 设置一个新的 Pojo 语句创建器
     * 
     * @param pojoMaker
     *            Pojo 语句创建器
     */
    public void setPojoMaker(PojoMaker pojoMaker) {
        this.pojoMaker = pojoMaker;
    }

    /**
     * @return 当前的 JDBC 专家类
     */
    public JdbcExpert getJdbcExpert() {
        return expert;
    }

    /**
     * 设置新的数据源。
     * 

* 如果有老的数据源需要你在外部手动关闭 * * @param ds * 数据源 */ public void setDataSource(DataSource ds) { setDataSource(ds,false); } public void setDataSource(DataSource ds,boolean isLazy) { if (null != dataSource) if (log.isWarnEnabled()) log.warn("Replaced a running dataSource!"); dataSource = ds; if (expert == null) expert = Jdbcs.getExpert(ds); pojoMaker = new NutPojoMaker(expert); meta = new DatabaseMeta(); final Set keywords = new HashSet(Daos.sql2003Keywords()); run(new ConnCallback() { public void invoke(Connection conn) throws Exception { DatabaseMetaData dmd = conn.getMetaData(); meta.setProductName(dmd.getDatabaseProductName()); meta.setVersion(dmd.getDatabaseProductVersion()); log.debug("JDBC Driver --> " + dmd.getDriverVersion()); log.debug("JDBC Name --> " + dmd.getDriverName()); if (!Strings.isBlank(dmd.getURL())) log.debug("JDBC URL --> " + dmd.getURL()); if (dmd.getDriverName().contains("mariadb") || dmd.getDriverName().contains("sqlite")) { log.warn("Auto-select fetch size to Integer.MIN_VALUE, enable for ResultSet Streaming"); SqlContext.DEFAULT_FETCH_SIZE = Integer.MIN_VALUE; } String tmp = dmd.getSQLKeywords(); if (tmp != null) { for (String keyword : tmp.split(",")) { keywords.add(keyword.toUpperCase()); } } if (log.isDebugEnabled() && meta.isMySql()) { String sql = "SHOW VARIABLES LIKE 'character_set%'"; Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql); while (rs.next()) log.debugf("Mysql : %s=%s", rs.getString(1), rs.getString(2)); rs.close(); // 打印当前数据库名称 String dbName = ""; rs = stmt.executeQuery("SELECT DATABASE()"); if (rs.next()) { dbName = rs.getString(1); log.debug("Mysql : database=" + dbName); } rs.close(); // 打印当前连接用户及主机名 rs = stmt.executeQuery("SELECT USER()"); if (rs.next()) log.debug("Mysql : user=" + rs.getString(1)); rs.close(); stmt.close(); // 列出所有MyISAM引擎的表,这些表不支持事务 PreparedStatement pstmt = conn.prepareStatement("SELECT TABLE_NAME FROM information_schema.TABLES where TABLE_SCHEMA = ? and engine = 'MyISAM'"); pstmt.setString(1, dbName); rs = pstmt.executeQuery(); if (rs.next()) log.debug("Mysql : '"+rs.getString(1) + "' engine=MyISAM"); rs.close(); pstmt.close(); } } }); if (log.isDebugEnabled()) log.debug("Database info --> " + meta); expert.setKeywords(keywords); if(!isLazy) { holder = new EntityHolder(this); holder.maker = createEntityMaker(); } setRunner(runner); setExecutor(executor); } public void execute(final Sql... sqls) { for (Sql sql : sqls) expert.formatQuery(sql); _exec(sqls); } public void run(ConnCallback callback) { runner.run(dataSource, callback); } protected int _exec(final DaoStatement... sts) { // 看看是不是都是 SELECT 语句 boolean isAllSelect = true; for (DaoStatement st : sts) { if (!st.isSelect()) { isAllSelect = false; break; } } // 这个是具体执行的逻辑,作为一个回调 // 后面的逻辑是判断到底应不应该在一个事务里运行它 DaoExec callback = new DaoExec(sts); // 如果强制没有事务或者都是 SELECT,没必要启动事务 boolean useTrans = false; switch (meta.getType()) { case PSQL: useTrans = true; break; case SQLITE: Transaction t = Trans.get(); useTrans = (t != null && (t.getLevel() == Connection.TRANSACTION_SERIALIZABLE || t.getLevel() == Connection.TRANSACTION_READ_UNCOMMITTED)); break; default: useTrans = !(Trans.isTransactionNone() && (sts.length==1 || isAllSelect)); break; } if (!useTrans) { run(callback); } // 否则启动事务 // wendal: 还是很有必要的!!尤其是解决insert的@Prev/@Next不在同一个链接的问题 else { Trans.exec(autoTransLevel, callback); } // 搞定,返回结果 ^_^ return callback.re; } /** * 子类可以重写这个类,用来扩展成其他的实体配置方式 * * @return 实体工厂 */ protected EntityMaker createEntityMaker() { return new AnnotationEntityMaker(dataSource, expert, holder); } /** * * @author wendal * @since 1.b.44 */ protected class DaoExec implements Atom, ConnCallback { private DaoStatement[] sts; private int re; public DaoExec(DaoStatement... sts) { this.sts = sts; } public void run() { DaoSupport.this.run(this); } public void invoke(Connection conn) throws Exception { for (DaoStatement st : sts) { if (st == null) { if (log.isInfoEnabled()) log.info("Found a null DaoStatement(SQL), ingore it ~~"); continue; } executor.exec(conn, st); re += st.getUpdateCount(); } } } public PojoMaker pojoMaker() { return pojoMaker; } public void setAutoTransLevel(int autoTransLevel) { this.autoTransLevel = autoTransLevel; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy