package org.nutz.dao.impl; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import javax.sql.DataSource; import org.nutz.dao.ConnCallback; import org.nutz.dao.DaoInterceptor; import org.nutz.dao.DaoInterceptorChain; 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.interceptor.DaoLogInterceptor; import org.nutz.dao.impl.interceptor.DaoTimeInterceptor; 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.Lang; import org.nutz.lang.Mirror; import org.nutz.lang.Strings; import org.nutz.lang.util.Callback; import org.nutz.log.Log; import org.nutz.log.Logs; /** * Dao 接口实现类的一些基础环境 * * @author zozoh(zozohtnt@gmail.com) */ 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; /** * 数据库的描述 */ protected DatabaseMeta meta; /** * SQL 管理接口实现类 */ protected SqlManager sqlManager; protected int autoTransLevel = Connection.TRANSACTION_READ_COMMITTED; protected List<DaoInterceptor> _interceptors; public DaoSupport() { this.runner = new NutDaoRunner(); this.executor = new NutDaoExecutor(); this.setInterceptors(Lang.list((Object)"log")); } /** * @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; } /** * 设置新的数据源。 * <p> * 如果有老的数据源需要你在外部手动关闭 * * @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); log.debug("select expert : " + expert.getClass().getName()); pojoMaker = new NutPojoMaker(expert); meta = new DatabaseMeta(); final Set<String> keywords = new HashSet<String>(Daos.sql2003Keywords()); run(new ConnCallback() { public void invoke(Connection conn) throws Exception { try { 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()); } } expert.checkDataSource(conn); } catch (Exception e) { log.info("something wrong when checking DataSource", e); } } }); if (log.isDebugEnabled()) log.debug("Database info --> " + meta); expert.setKeywords(keywords); if(!isLazy) { holder = new EntityHolder(this.expert, new Callback<ConnCallback>() { public void invoke(ConnCallback obj) { run(obj); } }); 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) { if (sts != null) for (DaoStatement ds : sts) { ds.setExpert(expert); } final DaoInterceptorChain callback = new DaoInterceptorChain(sts); callback.setExecutor(executor); callback.setAutoTransLevel(autoTransLevel); callback.setInterceptors(Collections.unmodifiableList(this._interceptors)); run(callback); // 搞定,返回结果 ^_^ return callback.getUpdateCount(); } /** * 子类可以重写这个类,用来扩展成其他的实体配置方式 * * @return 实体工厂 */ protected EntityMaker createEntityMaker() { return new AnnotationEntityMaker(dataSource, expert, holder); } public PojoMaker pojoMaker() { return pojoMaker; } public void setAutoTransLevel(int autoTransLevel) { this.autoTransLevel = autoTransLevel; } public void setInterceptors(List<Object> interceptors) { List<DaoInterceptor> list = new LinkedList<DaoInterceptor>(); for (Object it : interceptors) { DaoInterceptor d = makeInterceptor(it); if (d != null) list.add(d); } this._interceptors = list; } public void addInterceptor(Object it) { DaoInterceptor d = makeInterceptor(it); if (d != null) { List<DaoInterceptor> list = new LinkedList<DaoInterceptor>(this._interceptors); list.add(d); this._interceptors = list; } } public DaoInterceptor makeInterceptor(Object it) { if (it == null) return null; if (it instanceof String) { String itName = it.toString().trim(); if ("log".equals(itName)) { return new DaoLogInterceptor(); } else if ("time".equals(itName)) { return new DaoTimeInterceptor(); } else if (itName.contains(".")) { Class<?> klass = Lang.loadClassQuite(itName); if (klass == null) { log.warn("no such interceptor name="+itName); } else { return (DaoInterceptor) Mirror.me(klass).born(); } } else { log.info("unkown interceptor name="+itName); } } else if (it instanceof DaoInterceptor) { return (DaoInterceptor) it; } else { log.info("unkown interceptor -> "+it); } return null; } public DataSource getDataSource() { return dataSource; } }