package jef.database;
import java.lang.reflect.Type;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import jef.common.wrapper.IntRange;
import jef.database.dialect.type.AutoIncrementMapping;
import jef.database.meta.ITableMetadata;
import jef.database.query.SqlExpression;
import jef.database.wrapper.ResultIterator;
import jef.database.wrapper.populator.Transformer;
/**
* SQL操作工具类,这个对象指向单个特定的数据源。并且可以在这个数据源上执行各种SQL / JPQL/存储过程 相关的操作
*
*
*/
public interface SqlTemplate {
/**
* 得到数据库元数据管理器
* @return 元数据管理器
* @throws SQLException
* @see DbMetaData
*/
public DbMetaData getMetaData() throws SQLException;
/**
* 创建Native查询
* @param sqlString E-SQL
* @param clz 返回类型
* @return 查询对象(NativeQuery)
* @throws SQLException
* @see NativeQuery
* @see Session#createNativeQuery(String, Class)
*/
public <T> NativeQuery<T> createNativeQuery(String sqlString, Class<T> clz) throws SQLException;
/**
* 创建Native查询
* @param sqlString E-SQL
* @param meta 返回结果的元数据类型
* @return 查询对象(NativeQuery)
* @throws SQLException
* @see NativeQuery
* @see Session#createNativeQuery(String, ITableMetadata)
*/
public <T> NativeQuery<T> createNativeQuery(String sqlString, ITableMetadata meta) throws SQLException;
/**
* 创建JPQL查询
* @param jpql JPQL语句
* @param resultClass 返回结果类型
* @return 查询对象(NativeQuery)
* @throws SQLException
* @see NativeQuery
* @see Session#createQuery(String, Class)
*/
public <T> NativeQuery<T> createQuery(String jpql, Class<T> resultClass) throws SQLException;
/**
* 调用存储过程
* @param procedureName 存储过程名
* @param paramClass 存储过程的入参和出参
* @return 存储过程调用(NativeCall)
* @throws SQLException
* @see NativeCall
* @see Session#createNativeCall(String, Type...)
*/
public NativeCall createNativeCall(String procedureName, Type... paramClass) throws SQLException;
/**
* 创建匿名过程(匿名块)
* @param callString 匿名块代码
* @param paramClass 存储过程的入参和出参
* @return 存储过程调用(NativeCall)
* @throws SQLException
* @see NativeCall
* @see Session#createAnonymousNativeCall(String, Type...)
*/
public NativeCall createAnonymousNativeCall(String callString, Type... paramClass) throws SQLException;
/**
* 使用原生SQL分页查询。
*
* <h3>什么是原生SQL</h3>
* 原生SQL和NativeQuery不同。凡是NativeQuery系列的方法都是对SQL进行解析和改写处理的,而原生SQ不作任何解析和改写,直接用于数据库操作。<p>
*
* 原生SQL中,绑定变量占位符和E-SQL不同,用一个问号表示——<pre><tt>select * from t_person where id=? and name like ?</tt></pre>
*
* 原生SQL适用于不希望进行SQL解析和改写场合,一般情况下用在SQL解析器解析不了的SQL语句上,用作规避手段。<br>
* 建议,在需要保证应用的可移植性的场合下,尽可能使用{@link #createNativeQuery(String, Class)}代替。
*
* <h3>SQL中不必写分页逻辑</h3>
* 在分页时,EF-ORM依然会尝试改写SQL语句去查询count。
*
* @param sql 原生SQL语句
* @param returnType 查询返回类型
* @param pageSize 每页大小
* @return
* @throws SQLException
*/
public <T> PagingIterator<T> pageSelectBySql(String sql, Class<T> returnType, int pageSize) throws SQLException;
/**
* 使用原生SQL分页查询。
*
* <h3>什么是原生SQL</h3>
* 原生SQL和NativeQuery不同。凡是NativeQuery系列的方法都是对SQL进行解析和改写处理的,而原生SQ不作任何解析和改写,直接用于数据库操作。<p>
*
* 原生SQL中,绑定变量占位符和E-SQL不同,用一个问号表示——<pre><tt>select * from t_person where id=? and name like ?</tt></pre>
*
* 原生SQL适用于不希望进行SQL解析和改写场合,一般情况下用在SQL解析器解析不了的SQL语句上,用作规避手段。<br>
* 建议,在需要保证应用的可移植性的场合下,尽可能使用{@link #createNativeQuery(String, Class)}代替。
*
* <h3>SQL中不必写分页逻辑</h3>
* 在分页时,EF-ORM依然会尝试改写SQL语句去查询count。
*
* @param sql 原生SQL语句
* @param meta 查询返回类型的元数据
* @param pageSize 每页大小
* @return
* @throws SQLException
*/
public <T> PagingIterator<T> pageSelectBySql(String sql, ITableMetadata meta, int pageSize) throws SQLException;
/**
* 使用JPQL进行查询
* <br>
* EF并未实现JPQL的大部分功能。目前提供的JPQL功能其实只有将Java字段名替换为数据库列名的功能,离JPA规范的JPQL差距较大,而且由于设计理念等差异,要完整支持JPQL基本不可能。
* 现有若干伪JPQL功能是早期遗留的产物,后来在对SQL的特性作了大量改进后,E-SQL成为EF-ORM主要的查询语言。JPQL方面暂无改进计划,因此不建议使用。
*
* @param jpql JPQL语句
* @param resultClz 返回结果
* @param params 绑定变量参数
* @return 查询结果
* @throws SQLException
*/
public <T> List<T> selectByJPQL(String jpql,Class<T> resultClz,Map<String,Object> params) throws SQLException;
/**
* 执行JPQL语句
* <br>
* EF并未实现JPQL的大部分功能。目前提供的JPQL功能其实只有将Java字段名替换为数据库列名的功能,离JPA规范的JPQL差距较大,而且由于设计理念等差异,要完整支持JPQL基本不可能。
* 现有若干伪JPQL功能是早期遗留的产物,后来在对SQL的特性作了大量改进后,E-SQL成为EF-ORM主要的查询语言。JPQL方面暂无改进计划,因此不建议使用。
*
* @param jpql JPQL语句
* @param params 绑定变量参数
* @return 影响的记录行数
* @throws SQLException
*/
public int executeJPQL(String jpql,Map<String,Object> params) throws SQLException;
/**
* 使用原生SQL查询出一个long型数值
* {@linkplain #executeSql(String, Object...) 什么是原生SQL}
*
* 相当于
* {@linkplain #selectBySql(String, Long,class, Object...)}
* @param countSql 查询的语句,应该是一个count语句
* @param params 查询参数
* @return 查询结果
* @throws SQLException
*/
public long countBySql(String countSql, Object... params) throws SQLException ;
/**
* 执行原生SQL语句
* <h3>什么是原生SQL</h3>
* 原生SQL和NativeQuery不同。凡是NativeQuery系列的方法都是对SQL进行解析和改写处理的,而原生SQ不作任何解析和改写,直接用于数据库操作。<p>
*
* 原生SQL中,绑定变量占位符和E-SQL不同,用一个问号表示——<pre><tt>select * from t_person where id=? and name like ?</tt></pre>
*
* 原生SQL适用于不希望进行SQL解析和改写场合,一般情况下用在SQL解析器解析不了的SQL语句上,用作规避手段。<br>
* 建议,在需要保证应用的可移植性的场合下,尽可能使用{@link #createNativeQuery(String, Class)}代替。
*
* @param sql SQL语句
* @param params 绑定变量
* @return 影响的记录条数
* @throws SQLException
*/
public int executeSql(String sql, Object... params) throws SQLException;
/**
* 使用原生SQL语句加载一条记录。
* {@linkplain #executeSql(String, Object...) 什么是原生SQL}
*
* @param sql SQL语句
* @param t 返回结果类型
* @param params 绑定变量
* @return 查询结果
* @throws SQLException 除了查询错误的情况外,如果查询结果不止一条,也会抛出此异常
*/
public <T> T loadBySql(String sql,Class<T> t,Object... params) throws SQLException;
/**
* 使用原生SQL查询,
* {@linkplain #executeSql(String, Object...) 什么是原生SQL}
*
* @param sql SQL语句
* @param resultClz 需要的返回结果类型
* @param params 绑定变量
* @return 查询结果
* @throws SQLException
*/
public <T> List<T> selectBySql(String sql, Class<T> resultClz, Object... params) throws SQLException;
/**
* 使用原生SQL查询,
* {@linkplain #executeSql(String, Object...) 什么是原生SQL}
* @param sql SQL语句
* @param transformer 查询结果转换器
* @param range 分页范围(是一个含头含尾的区间对象)
* @param params 绑定变量
* @return 查询结果
* @throws SQLException
*/
public <T> List<T> selectBySql(String sql, Transformer transformer, IntRange range, Object... params) throws SQLException;
/**
* 使用原生SQL查询,返回的遍历器, 遍历器模式查找一般用于超大结果集的返回。
* {@linkplain #executeSql(String, Object...) 什么是原生SQL}<br>
*
* <h3>作用</h3> 当结果集超大时,如果用List<T>返回,内存占用很大甚至会溢出。<br>
* JDBC设计时考虑到这个问题,因此其返回的ResultSet对象只是查询结果视图的一段,用户向后滚动结果集时,数据库才将需要的数据传到客户端。
* 如果客户端不缓存整个结果集,那么前面已经滚动过的结果数据就被释放。<p>
* 这种处理方式实际上是一种流式处理模型,iteratedSelect就是这种模型的封装。<br>
* iteratedSelect并不会将查询出的所有数据放置到一个List对象中(这常常导致内存溢出)。而是返回一个Iterator对象,用户不停的调用next方法向后滚动,
* 同时释放掉之前处理过的结果对象。这就避免了超大结果返回时内存溢出的问题。
* <h3>注意事项</h3> 由于 ResultIterator
* 对象中有尚未关闭的ResultSet对象,因此必须确保使用完后关闭ResultIteratpr.如下示例
* <pre><tt>ResultIterator<TestEntity> iter = db.iteratorBySql(sql,new Transformer(TestEntity.class), 0, 0);
* try{
* for(; iter.hasNext();) {
* iter.next();
* //do something.
* }
* }finally{
* //必须在finally块中关闭。否则一旦业务逻辑抛出异常,则ResultIterator未释放造成游标泄露.
* iter.close();
* }</tt></pre>如果ResultSet不释放,相当于数据库上打开了一个不关闭的游标,而数据库的游标数是很有限的,耗尽后将不能执行任何数据库操作。<br>
*
* @param sql 原生SQL语句
* @param transformers 结果转换器
* @param maxReturn 最多返回结果数据
* @param fetchSize JDBC获取每批大小。
* @param objs 绑定变量参数
* @return
* @throws SQLException
*/
public <T> ResultIterator<T> iteratorBySql(String sql, Transformer transformers,int maxReturn, int fetchSize,Object... objs) throws SQLException;
/**
* 指定一条原生SQL语句,批量执行多次。
* {@linkplain #executeSql(String, Object...) 什么是原生SQL}
*
* @param sql
* 要执行的SQL语句
* @param params
* 绑定变量,每个List<?>是一组数据(相当于SQL执行一次)。可以传入多组数据
* @return 查询影响记录行数(总计)
* @throws SQLException
*/
public int executeSqlBatch(String sql, List<?>... params) throws SQLException;
/**
* 得到SQL表达式的值。因为不同的数据库语法不同,例如
* <code>
* <ul>select [expression] from dual; //Oracle</ul>
* <ul>select [expression]; //MySQL</ul>
* <ul>values [expression]; //Derby</ul>
* </code>
* 使用此方法,只需传入表达式本身,SQL语句会根据当前数据库自动生成
*
* @param expression 表达式
* @param clz 返回结果类型
* @param 绑定变量的值
* @return 根据表达式查询出来的结果
*/
public <T> T getExpressionValue(String expression,Class<T> clz,Object... params)throws SQLException;
/**
* 得到SQL函数的值。因为不同的数据库语法不同,例如
* <code>
* <ul>select [expression] from dual; //Oracle</ul>
* <ul>select [expression]; //MySQL</ul>
* <ul>values [expression]; //Derby</ul>
* </code>
* 使用此方法,只需传入表达式本身,SQL语句会根据当前数据库自动生成
*
* @param func 函数
* @param clz 返回结果类型
* @param params 函数参数
* @return 根据函数查询出来的结果
*/
public <T> T getExpressionValue(DbFunction func,Class<T> clz,Object... params)throws SQLException;
/**
* 返回数据库函数表达式。
*
* @param func
* {@link jef.database.query.Func}
* @param params
* 参数
* @return 函数表达式
*/
public SqlExpression func(DbFunction func, Object... params) ;
/**
* 获得Sequence
* @param mapping Sequence所在列的元数据定义
* @return Sequence
* @throws SQLException
* @see Sequence
*/
public Sequence getSequence(AutoIncrementMapping mapping) throws SQLException;
/**
* 获得Sequence
* @param seqName Sequence名称
* @param i 最大位数
* @return Sequence
* @throws SQLException
* @see Sequence
*/
public Sequence getSequence(String seqName, int i)throws SQLException;
}