
最常用的 log4jproperties 来实现。
log4jproperties 内容如下:
log4jrootCategory=info, stdout , R
log4jappenderstdout=orgapachelog4jConsoleAppender
log4jappenderstdoutlayout=orgapachelog4jPatternLayout
log4jappenderstdoutlayoutConversionPattern=[QC] %p [%t] %C%M(%L) | %m%n
log4jappenderR=orgapachelog4jDailyRollingFileAppender
log4jappenderRFile=D:/my_loglog
log4jappenderRlayout=orgapachelog4jPatternLayout
log4jappenderRlayoutConversionPattern=%d-[TS] %p %t %c - %m%n
log4jloggercomibatis=debug
log4jloggercomibatiscommonjdbcSimpleDataSource=debug
log4jloggercomibatiscommonjdbcScriptRunner=debug
log4jloggercomibatissqlmapengineimplSqlMapClientDelegate=debug
log4jloggerjavasqlConnection=debug
log4jloggerjavasqlStatement=debug
log4jloggerjavasqlPreparedStatement=debug,stdout
有人在网上说不能用 slf4jjar ,这个说法应该是错误的, slf4j 只是提供了很多接口,可以供很多日志系统用,并不是具体的解决方案,我的jar 包用到
slf4j-api-158jar
slf4j-log4j12-158jar
log4j-1215jar
貌似版本比较老,但可以使用,可以参考一下。
通过这种方式mybatis 就可以在控制台打印出sql语句,并且也可以写到日志文件中去。但是还没有format sql, 我也在研究,不过目前没进展,应该mybatis 不支持吧。
oracle 10g的DBMS_XPLAN包中display_cursor函数不同于display函数,display_cursor用于显示SQL语句的真实的执行计划,在大多数情况下,
显示真实的执行计划有助于更好的分析SQL语句的全过程,尤其是运行此SQL语句实时的I/O开销。通过对比预估的I/O与真实的I/O开销来判断
SQL语句所存在问题,如缺少统计信息,SQL语句执行的次数,根据实际中间结果集的大小来选择合适的连接方式等。本文仅仅讲述
display_cursor函数的使用。
一、display_cursor函数用法
1、display_cursor函数语法
DBMS_XPLANDISPLAY_CURSOR(
sql_id IN VARCHAR2 DEFAULT NULL,
cursor_child_no IN NUMBER DEFAULT NULL,
format IN VARCHAR2 DEFAULT 'TYPICAL');
2、display_cursor函数参数描述
sql_id
指定位于库缓存执行计划中SQL语句的父游标。默认值为null。当使用默认值时当前会话的最后一条SQL语句的执行计划将被返回
可以通过查询V$SQL 或V$SQLAREA的SQL_ID列来获得SQL语句的SQL_ID。
cursor_child_no
指定父游标下子游标的序号。即指定被返回执行计划的SQL语句的子游标。默认值为0。如果为null,则sql_id所指父游标下所有子游标
的执行计划都将被返回。
format
控制SQL语句执行计划的输出部分,即哪些可以显示哪些不显示。使用与display函数的format参数与修饰符在这里同样适用。
除此之外当在开启statistics_level=all时或使用gather_plan_statistics提示可以获得执行计划中实时的统计信息
有关详细的format格式描述请参考:dbms_xplan之display函数的使用 中format参数的描述
下面给出启用统计信息时format新增的修饰符
iostats 控制I/O统计的显示
last 默认,显示所有执行计算过的统计。如果指定该值,则只显示最后一次执行的统计信息
memstats 控制pga相关统计的显示
allstats 此为iostats memstats的快捷方式,即allstats包含了iostats和memstats
run_stats_last 等同于iostats last。只能用于oracle 10g R1
run_stats_tot 等同于iostats。只能用于oracle 10g R1
抓一个最近一小时最消耗IO的SQL:
SELECT sql_id, COUNT()
FROM gv$active_session_history ash, gv$event_name evt
WHERE ashsample_time > SYSDATE - 1 / 24
AND ashsession_state = 'WAITING'
AND ashevent_id = evtevent_id
AND evtwait_class = 'User I/O'
GROUP BY sql_id
ORDER BY COUNT() DESC;
执行上面的SQL:
SQL> SELECT sql_id, COUNT()
FROM gv$active_session_history ash, gv$event_name evt
2 3 WHERE ashsample_time > SYSDATE - 1 / 24
4 AND ashsession_state = 'WAITING'
5 AND ashevent_id = evtevent_id
6 AND evtwait_class = 'User I/O'
7 GROUP BY sql_id
8 ORDER BY COUNT() DESC;
SQL_ID COUNT()
------------- ----------
g7fu6qba82m6b 668
63r47zyphdk06 526
9f5m4wd88nc1h 514
593p47drw5fhk 232
br91w16jzy4fu 120
4fvwyjpnh6tp7 78
gm0nrbfuj8kzr 70
2184k363hw4xd 68
gc4dajs7g5myy 46
8vrk9sfuwfdgq 42
ccpnb4dwdmq21 40
查看SQL的执行计划:
SELECT FROM TABLE(dbms_xplandisplay_cursor('g7fu6qba82m6b'));
在SQLPLUS中执行:
SQL> set pagesize 2000
SQL> SELECT FROM TABLE(dbms_xplandisplay_cursor('g7fu6qba82m6b'));
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
SQL_ID g7fu6qba82m6b, child number 0
-------------------------------------
UPDATE "CPDDS_PDATA""CDM_LEDGER" SET "CSTM_NAME" = :a1,"CSTM_NO" =
:a2,"PAPER_TYPE" = :a3,"PAPER_NO" = :a4,"CURR_TYPE" = :a5,"SVT_NO" =
:a6,"BAL_DIR" = :a7,"BAL" = :a8,"AVAL_BAL" = :a9,"NORM_FRATIO" =
:a10,"PK_BAL" = :a11,"DR_ACCU" = :a12,"CR_ACCU" = :a13,"LAST_TRAN_DATE" =
:a14,"LAST_TRAN_TIME" = :a15,"PRT_LINE_NUM" = :a16,"NOREG_PK_REC_NUM" =
:a17,"PK_NO" = :a18,"PWD" = :a19,"FLAG" = :a20,"FRZ_FLAG" =
:a21,"CARD_HOLD_FLAG" = :a22,"PK_HOLD_FLAG" = :a23,"BGN_INT_DATE" =
:a24,"OPEN_DATE" = :a25,"ACC_HOLD_FLAG" = :a26,"CLS_DATE" =
:a27,"OPEN_TLR" = :a28,"CLS_TLR" = :a29,"CLS_INT" = :a30,"OPEN_INST" =
:a31,"ADD_NUM" = :a32,"DAC" = :a33,"FRZ_TIMES1" = :a34,"FRZ_TIMES2" =
:a35,"HOST_SEQNO" = :a36,"D_UPDATE_DATE" = :a37 WHERE "ACC" = :b0
Plan hash value: 319441092
-----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------
| 0 | UPDATE STATEMENT | | | | 3 (100)| |
| 1 | UPDATE | CDM_LEDGER | | | | |
| 2 | INDEX UNIQUE SCAN| I_CDM_LEDGER | 1 | 269 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ACC"=:B0)
29 rows selected
总结
1、与display函数不同,display_cursor显示的为真实的执行计划
2、对于format参数,使用与display函数的各个值,同样适用于display_cursor函数
3、当statistics_level为all或使用gather_plan_statistics提示可以获得执行时的统计信息
4、根据真实与预估的统计信息可以初步判断SQL效率低下的原因,如统计信息的准确性、主要的开销位于那些步骤等
比如我们在引入了jdbc的配置文件使用了properties标签,引入jdbc有什么好处?,可以在配置文件中统一管理
内容而不是在很多个文件改来改去,而且在核心配置文件中把数据库连接相关的写死,显然是硬编码的所以我们用配置文件代替 nice!!!
你可能注意到了上面的写法 用前缀jdbc 可以很好地将他们与其他的变量区分开,(可以从名字很容易看出是jdbc相关的数据,不至于和同名变量搞混因为username这种可能
不止会出现在数据库的连接)
上面的代码中引入配置文件的部分为
可以从上面看到写法:
下面这段就是用来设置类的别名:
那么问题来了,为什么要有类的别名这种 *** 作??
因为在映射文件中每次都要写全类名显然有点麻烦比如下面这样:
一个项目是会有很多个映射文件的为了方便,所以类别名就出现了。可以在核心配置文件写接口类和对应的别名
这样就可以在映射文件的命名空间里可以直接写User(对大小没有要求也可以是user; 其实可以比这更加简单,也是我们在实际开发中常用的写法
就是将整个包写成别名的形式,如果不写alias属性默认为类名(不区分大小写),这样就容易多了,我们只需一行代码,便可以在所有的映射文件命名空间
中直接写对应的类名
引入核心的配置文件
首先需要思考的这里是映射文件的引入,我们正常的一个项目的数据库是有很多个表组成的那么每一张表对应一个mapper接口,每个接口对应一个映射文件,那么就需要导入大量的映射文件,还容易漏掉-->
上面这种以包的形式的导入非常方便,不用每次新建一个接口就要导入它的映射文件,但是上面这种写法需要 注意 一些问题:
如果你在映射文件中编写查询语句的sql,但是粗心的你忘记了设置返回类型会在控制台抛异常且会看到这样的说明:
It's likely that neither a Result Type nor a Result Map was specified
下面只是指定返回类型的一种方式:resultType,还有 resultMap
它们的区别:
查询的标签必须指定resultType或resultMap
comkobedumybatis 获取参数的两种方式:${} 和 #{}
上面是使用了 #{}写法相当于原生jdbc的占位符,这个前面已经提到过了所以不多赘述, 需要注意的是#{}里面的变量名可以是任意的username规范显然很好,但是aaaa也没错因为只是用来占位的;
还有就是在使用${}时注意''单引号问题,因为${}是字符拼接的方式,所以需要注意!!
传输参数时有多个参数时
在测试代码里通过传入两个参数分别为 username和password 但是在上面代码的(映射文件里的部分代码)执行失败,(sql语句未能解析)
报错:
Cause: orgapacheibatisbindingBindingException: Parameter 'username' not found Available parameters are [arg1, arg0, param1, param2]
可以从错误提示的信息不难发现我们的参数在映射文件里未能真正地接受到,可以用[arg1, arg0, param1, param2] 的方式获取,mybatis将参数放到map容器可以通过建arg0,agr1的方式
获取参数(也可以是param1,param2)
将上面的代码改动:
需要注意的是:使用${}时需要手动添加''才能正常访问,因为他的处理方式是字符串的拼接
做了改动之后结果很感人!!
User{id=6, userName='旺财', age=20, password='cwlz'}
可以直接通过键访问相对应的值(通过自己的方式访问到数据,上面的形式是mybatis默认提供的map和mybatis默认的提取指的方式 arg0,arg2)
当需要传多个参数时将他们放到一个map容器,然后将map传给对应的方法(模拟mybatis的做法,就可以在sql语句中直接通过键访问到值)代码如下:
映射文件中的部分代码 :
通过键直接获取值,注意:使用${}时不要忘了单引号!!!!
当参数以实体对象的形式传参时如何解决?
只需要通过#{}以属性名的方式访问!
所以代码的编写一定要规范,才能减少这种错误!!!
一定要和注解中的参数名一一对应!!!
如果查询的结果只有一个,也可以通过Map集合接收,字段名为键字段的值为值:{password=0000, id=3, userName=图区, age=20}
javalangIngeger --> int ,Integer
int --> _int,_Integer
Map --> map
String --> string
注意:
所以在批量删除的案例:需要注意的是不能使用#{} 因为它是会自动添加'' 所以在批量删除的语句中我们要使用${}
若字段和属性名不一致 ,则可以通过resultMap设置自定义映射
在mybatis的核心配置文件用下面的代码将 数据库中命名的规范 (user_name) 转换为 java中的命名规范 (userName)
就是手动设置属性与字段的映射关系:
如果设置了手动的设置属性和字段的映射关系,注意主键使用 id 标签,普通字段使用 result标签,就算属性和字段名一一对应,只要
用了这种方式就 必须要写全 !!!
一对多的查询:
通过分步查询实现:
多条件的查询
if 根据标签中test的属性所对应的表达式决定标签中的内容是否拼接到sql语句中
上面的where后面的 1=1 是细节,因为当where后面的条件都为空时就成了 select from t_user where
显然这种sql语句是有问题的,还有一种情况就是当userName为null时语句就成了 select from t_user where and age=#{age}
这也是错的,所以在where后加一个恒成立的条件不仅不会影响查询结果,而且没有会在特定情况时sql语句是会报错的所以很有必要
where 当where标签中有内容时,会自动生成where关键字,并且将内容前多余的and 或者or去掉
当where中没有内容时,此时where标签没有任何效果 就是不会生成关键字 注意:在写条件时不能在后面加and or 这个在下一条语句无效时mybatis不会帮你去掉!
相当于 if else
一个案例 -->就是当我们需要批量删除一些东西时(参数以数组的形式传入)
sql 片段: 在我们的查询语句不能在实际开发中也一直写 ;因为我们要按需查找,不必将不需要的也查询出来,我们可以将我们平常查询次数较多的字段
放在sql片段内,可以在需要查询时直接进行引用!
缓存,这个术语我们听过很多次,在web阶段时访问网页时有缓存机制!
现在sql的查询时也有缓存机制,有一级缓存,一级缓存是默认开启的,一级缓存的范围时sqlSession,将我们查询到的数据先进行缓存,若下次有相同的查询时不用重新
访问数据库,可以直接从缓存中取出!!!!
手动清空缓存 sqlSessionclearCache();
在mapper配置文件中添加cache标签可以设置一些属性:
逆向工程就是不难理解,我们之前都是由实体类到数据库,而逆向类就是通过数据库表生成实体类,
<select id="getUserInfo" parameterType="javautilMap" resultMap="userResult">
SELECT TUUSERID, TUUSERNAME, TUPASSWORD, TUGROUPIDEN, TUROLEID
, TUIREALNAME, TUIGENDER, TUIBIRTHDAY, TUIPERSONID, TUIEMAIL, TUIMOBILENUMBER
<if test="#{group == 'MANAGER'} || #{group == 'COMPANY'}">
, TUSJOBNUMBER, TUSCOMPANYID FROM TAB_USER TU,
TAB_USER_INFO TUI, TAB_USER_STAFF TUS
</if>
<if test="#{group == 'CONSUMER'}">
, TUCADDRESS, TUCAREAID FROM TAB_USER TU,
TAB_USER_INFO TUI, TAB_USER_CONSUMER TUC
</if>
WHERE
<if test="#{group == 'MANAGER'} || #{group == 'COMPANY'}">
TUUSERID = TUIUSERID AND TUUSERID = TUSUSERID AND TUIUSERID = TUSUSERID AND TUUSERNAME = #{userName}
</if>
<if test="#{group == 'CONSUMER'}">
TUUSERID = TUIUSERID AND TUUSERID = TUCUSERID AND TUIUSERID = TUCUSERID AND TUUSERNAME = #{userName}
</if>
</select>
这样试试呢?
映射器配置文件
<select id="findAll" resultType="cntedunoteentityUser">
SELECT FROM cn_user;
</select>
测试代码
@Test
public void test2(){
UserDao dao = acgetBean("userDao",UserDaoclass);
Systemoutprintln(dao);
List<User> users = daofindAll();
Systemoutprintln(users);
for(User u : users){
//Systemoutprintln(u);
}
}
运行期间没报错,结果:
映射器对象获取成功了的,就是结果集为null值
orgapacheibatisbindingMapperProxy@28ffa4
[null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]
以上就是关于mybatis怎么获取生成的sql语句全部的内容,包括:mybatis怎么获取生成的sql语句、Mybatis 执行sql、mybatis各阶段的详解等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)