`
aol_aog
  • 浏览: 16865 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

从ET2开发中领悟到的

 
阅读更多

1、 设计表时,如果属于同种类型的字符串保存,可以使用分隔符来分隔保存数据,可以避免存储多条记录或多个字段;操作上只需在存储之前加上分隔符,读取时分割一下就可以了。

2、 对于标志之类的字段,如果可以使用01表示,那么可以设计在一个字段之类,使用每一位来表示不同的含义,可以利用的函数BITAND(位与运算)来判断标志位. 在存储过程中需要创建一个函数BITOR(位或运算)来设置标志位

create or replace function BITOR(x in number, y in number) return number is
Result number;
begin
Result:=(x + y) - BITAND(x, y);
return(Result);
end BITOR;

3、 对于数字或日期,可以使用trunc方法来截取指定长度的内容,该方法只截取,不做舍入。要做舍入使用round方法;日期天数加减直接使用+-号就可一了,月份加减使用add_months函数

4、 在实际使用中,经常会有带in的子查询,如where id in (1,2,3)这样的情况,但是如果很多这样的语句在数据库中出现,将引起数据库的大量硬解析与共享池SQL碎片。所以,在实际应用中,可以采用其他方法,将这些in list给绑定起来。
如果需要绑定in list,首先,需要创建两个类型(type)
针对数据类型的
CREATE OR REPLACE TYPE NUMTABLETYPE as table of number;
针对字符串类型的(每个list的单元大小不要超过1000字节)
create or replace type vartabletype as table of varchar2(1000);
然后创建两个相关的函数
数字列表函数

代码:

create or replace function str2numList( p_string in varchar2 ) return numTableType
as
v_str long default p_string ||
',';
v_n number;
v_data numTableType := numTableType();
begin
loop
v_n := to_number(instr( v_str,
',' ));
exit when (nvl(v_n,
0) = 0);
v_data.extend;
v_data( v_data.count ) := ltrim(rtrim(substr(v_str,
1,v_n-1)));
v_str := substr( v_str, v_n+
1 );
end loop;
return v_data;
end;

create or replace function str2varList( p_string in varchar2 ) return VarTableType
as
v_str long default p_string ||
',';
v_n number;
v_data VarTableType := VarTableType();
begin
loop
v_n :=instr( v_str,
',' );
exit when (nvl(v_n,
0) = 0);

v_data.extend;
v_data( v_data.count ) := ltrim(rtrim(substr(v_str,
1,v_n-1)));
v_str := substr( v_str, v_n+
1 );
end loop;
return v_data;
end;

创建之后,我们就可以采用如下的方式来使用in list的绑定了。如可以采用如下的三种方案

代码:

SELECT /*+ ordered use_nl(a,u) */ id, user_id, BITAND(promoted_type,4) busauth


from table(STR2NUMLIST(:bind0)) a,


bmw_users u


where u.user_id = a.column_value


SELECT/*+ leading(a) */ id, user_id, BITAND(promoted_type,4) busauth


from bmw_users u where user_id in


(select * from table(STR2NUMLIST(:bind0)) a);


SELECT/*+ index(bmw_users UK_BMW_USERS_USERID) */ id, user_id


from bmw_users where user_id in


(SELECT * FROM THE (SELECT CAST(STR2NUMLIST(:bind0) AS NUMTABLETYPE) FROM dual) WHERE rownum<1000)



在如上的方案中,以上语句中的hint提示,是为了稳定执行计划,防止Oraclein list的错误估计而导致走hash连接。一般建议采用第一种方法,比较简单可靠并且可以指定稳定的计划。但是要求数据库的版本比较高,在老版本中(8i),可能只能采用第三种方法。总的来说,12两种方法比3要少6个逻辑读左右

5、 程序中关键地方一定要打印日志,对日志进行分级打印,异常日志统一在业务层最高层进行处理,其他底层异常包装后直接向业务层抛出。日志信息一定要有助于日后错误查找,不要打只打印无用的系统出错啦等,而其他有用的信息都没有。

6、 如果是相关的一组常量,则可以考虑设计枚举来进行操作,例如:订单状态,并且将状态相关的操作都封装在枚举中进行操作。颜色等也可以进行类似的封装:

/**

* @author huanggang

* @since 2007-11-13下午05:21:31

*

*/

public enum Color {

Red(1) {// 红色

public Color nextColor() {

return Blue;

}

},

Blue(2) {// 蓝色

public Color nextColor() {

return Black;

}

},

Black(3) {// 黑色

public Color nextColor() {

return Red;

}

};

/**

* 保存实际的值,这个类型可以是Object等其他类型

*/

private int value;

private Color(int value) {

this.value = value;

}

/**

* 得到当前值

*

* @return

*/

public int getValue() {

return this.value;

}

/**

* 当前颜色的下一个颜色

* @return

*/

public abstract Color nextColor();

/**

* 是否是红色,其他颜色都可以这样定义

* @return

*/

public boolean isRed() {

return isRed(this.value);

}

public boolean isRed(int value){

return Red.value==value;

}

}

7、 鉴于网络上对于ibatis的缓存介绍不够详细,特别是对于session的概念没有明确指出,都是人云亦云sqlMapClient相当于一个session,本人阅读了ibatis源代码,得出如下结论:

Ibatis一个sqlMapClient实例对应一个SqlMapExecutorDelegate实例,如果sqlMap被多线程执行,那么会共享这两个实例,ibatis对于每个线程都会创建一个SqlMapSessionImpl实例来表示session这个概念,每个线程的数据库操作方法都在本session内执行,SqlMapExecutorDelegate保存了一个ThreadLocal来保存最大同时能够运行的session数目,也就是配置文件中的maxSessions="800"。一个SqlMapSessionImpl对应ThreadLocal中的一个session.当执行查询操作时,如果有缓存,ibatis会首先根据参数、statementid、缓存的idhash一个CacheKey出来,如果该缓存是是可读写缓存,那么将本sessionhash进去,然后以这个对象为key查找缓存,由于有了session的特征,这样对于每一个session中查询出的数据的修改都不会影响另一个session的数据。如果该缓存是只读缓存,则不将session的特征hash进去,意思就是说,该sqlmap实例中的所有session都可以共享这一个查询出来的数据,对数据的修改也会造成对另一个session读出数据的影响。

所以,按照这个道理,cache的配置中如果readonlytrue,则该sqlMap的所有session共享该实例,如果修改其中一个实例,那么会对其他session造成影响。如果readonlyfalse,由于该实例只是对该session有效,所以,修改也只会对本session有效。Serialize参数为true并且readonlyfalse时,将会对缓存数据进行序列化保存,读取时再反序列化。如果多个session访问,则Serialize会返回不反序列化之后的对象(相当于复制的对象,也可以这样理解,处理这一点和readonlytrue时不一样,其他处理方式都一样);当readonlytrue时,不论是否设置了Serialize,都会忽略该参数的设置,处理的结果和值设置readonly效果一样。

下面是两个关于该属性设置的关键代码,一读就明白了。(红色部分)

cacheModel.java 关键部分

/**

* Get an object out of the cache.

* A side effect of this method is that is may clear the cache if it has not been

* cleared in the flushInterval.

*

* @param key The key of the object to be returned

* @return The cached object (or null)

*/

public Object getObject(CacheKey key) {

synchronized (this) {

if (flushInterval != NO_FLUSH_INTERVAL

&& System.currentTimeMillis() - lastFlush > flushInterval) {

flush();

}

}

Object value = null;

synchronized (getLock(key)) {

value = controller.getObject(this, key);

}

if (serialize && !readOnly && (value != NULL_OBJECT && value != null)) {

try {

ByteArrayInputStream bis = new ByteArrayInputStream((byte[]) value);

ObjectInputStream ois = new ObjectInputStream(bis);

value = ois.readObject();

ois.close();

} catch (Exception e) {

throw new NestedRuntimeException("Error caching serializable object. Be sure you're not attempting to use " +

"a serialized cache for an object that may be taking advantage of lazy loading. Cause: " + e, e);

}

}

synchronized (STATS_LOCK) {

requests++;

if (value != null) {

hits++;

}

}

return value == NULL_OBJECT ? null : value;

}

/**

* Add an object to the cache

*

* @param key The key of the object to be cached

* @param value The object to be cached

*/

public void putObject(CacheKey key, Object value) {

if (null == value) value = NULL_OBJECT;

if (serialize && !readOnly && value != NULL_OBJECT) {

try {

ByteArrayOutputStream bos = new ByteArrayOutputStream();

ObjectOutputStream oos = new ObjectOutputStream(bos);

oos.writeObject(value);

oos.flush();

oos.close();

value = bos.toByteArray();

} catch (IOException e) {

throw new NestedRuntimeException("Error caching serializable object. Cause: " + e, e);

}

}

synchronized (getLock(key)) {

controller.putObject(this, key, value);

}

}

CachingStatement.java 关键部分

public CacheKey getCacheKey(RequestScope request, Object parameterObject) {

CacheKey key = statement.getCacheKey(request, parameterObject);

if (!cacheModel.isReadOnly() && !cacheModel.isSerialize()) {

key.update(request.getSession());

}

return key;

}
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics