MyBatis 配置中那些值得注意的坑
来源:互联网 发布:网络借贷资金存管 编辑:程序博客网 时间:2024/06/05 20:17
当你在使用Mybatis 时进行配置的时候有这样几个坑一定要注意下。
第一坑:Mybatis 的缓存机制
有时候你对数据库中的数据进行了增删改查操作,但是页面请求获取到的总不是最新的数据,这时候你就要检查是不是自己入坑了。
<setting name="cacheEnabled" value="true" /><setting name="localCacheScope" value="SESSION" />
MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。 默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession 的不同调用将不会共享数据。
Tips:
关于缓存配置,第一个设置一般都会设置成false,这个坑很少会进,但是第二个默认的值为session,这个就是一个大坑,一不留神你就可能进坑,如果你设置成了session 那么就会有缓存,当你对数据进行了修改,但是你每次的请求获取数据都不是最新的,你发现页面还是原来数据,但是数据库已经修改了。这在项目开发和使用中可是相当蛋疼的问题。
解决方案:
<setting name="cacheEnabled" value="false" /><setting name="localCacheScope" value="STATEMENT" />
第二坑:Mybatis数据库语句打印不出来
你有没有发现当你和struts2 或者springmvc 等其他框架整合后发现,想打印Mybatis 数据库语句却怎么样也打印不出来?
不少应用服务器的classpath中已经包含Commons Logging,如Tomcat和WebShpere,
所以MyBatis会把它作为具体的日志实现。记住这点非常重要。这将意味着,在诸如
WebSphere的环境中——WebSphere提供了Commons Logging的私有实现,你的Log4J配置将被忽略。这种做法不免让人悲催,MyBatis怎么能忽略你的配置呢?事实上,因Commons Logging已经存 在了,按照优先级顺序,Log4J自然就被忽略了!不过,如果你的应用部署在一个包含Commons Logging的环境, 而你又想用其他的日志框架,你可以通过在MyBatis的配置文件mybatis-config.xml里面添加一项setting(配置)来选择一个不同的日志实现。
官方提供的解决方案:
http://www.mybatis.org/mybatis-3/zh/logging.html
<configuration> <settings> ... <setting name="logImpl" value="LOG4J"/> ... </settings></configuration>
但是当你以为找到答案而欣喜时,按照官网这样配置后发现还是打印不出来SQL 语句?why?
<?xml version="1.0" encoding="UTF-8"?><Configuration> <Appenders> <Console name="STDOUT" target="SYSTEM_OUT"> <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n" /> </Console> <File name="MyFile" fileName="${log4j:configParentLocation}/logs/${date:yyyy-MM-dd}-application.log"> <PatternLayout> <Pattern>%d %p %c{1.} [%t] %m%n</Pattern> </PatternLayout> </File> </Appenders> <Loggers> <Logger name="com.opensymphony.xwork2" level="info" /> <Logger name="org.apache.struts2" level="info" /> <Logger name="yourcompany.com" level="error" /> <Root level="error"> <AppenderRef ref="STDOUT" /> <AppenderRef ref="MyFile" /> </Root> </Loggers></Configuration>
好吧,突然我不卖关子了,当你等级设置成info 或者error的时候,你是看不到SQL的,想看到打印的SQL语句只需要将等级设置为debug 即可。
正确配置如图所示:
<?xml version="1.0" encoding="UTF-8"?><Configuration> <Appenders> <Console name="STDOUT" target="SYSTEM_OUT"> <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n" /> </Console> <File name="MyFile" fileName="${log4j:configParentLocation}/logs/${date:yyyy-MM-dd}-application.log"> <PatternLayout> <Pattern>%d %p %c{1.} [%t] %m%n</Pattern> </PatternLayout> </File> </Appenders> <Loggers> <Logger name="com.opensymphony.xwork2" level="info" /> <Logger name="org.apache.struts2" level="info" /> <Logger name="yourcompany.com" level="debug" /> <Root level="debug"> <AppenderRef ref="STDOUT" /> <AppenderRef ref="MyFile" /> </Root> </Loggers></Configuration>
第三坑 数据源
dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
许多 MyBatis 的应用程序将会按示例中的例子来配置数据源。然而它并不是必须的。要知道为了方便使用延迟加载,数据源才是必须的。
有三种内建的数据源类型(也就是 type=”[UNPOOLED|POOLED|JNDI]”)
然而我们一般大多数都会选择POOLED 是不是?
<environments default="development"> <environment id="development"> <transactionManager type="JDBC"> <property name="..." value="..."/> </transactionManager> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment></environments>
只是这样来看似乎并没有什么大的问题,但是你有没有发现当你的tomcat 运行了一段时间后会挂掉?
iBatis自己带了一个simple的数据库连接池,基本的功能都有。但是在处理部分数据库(比如mysql)的连接空闲时间太长(mysql是8小时)自动超时的时候,就比不上象c3p0这样的连接池软件了(c3p0能自动处理数据库连接被关闭的情况)。
感谢博主:http://www.blogjava.net/usherlight/archive/2008/05/13/200164.html
解决方案:
<dataSource type="POOLED"><!-- 数据库连接池配置 --><!-- 在任意时间可以存在的活动(也就是正在使用)连接数量,默认值:10 --><property name="poolMaximumActiveConnections" value="300" /><!-- 任意时间可能存在的空闲连接数 默认是5,最好设置为0,否则可能会崩溃掉 --><property name="poolMaximumIdleConnections" value="0" /><!-- 在被强制返回之前,池中连接被检出(checked out)时间,默认值:20000 毫秒(即 20 秒) --><property name="poolMaximumCheckoutTime" value="20000" /><!-- 这是一个底层设置,如果获取连接花费的相当长的时间,它会给连接池打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直安静的失败),默认值:20000 毫秒(即 20 秒)。 --><property name="poolTimeToWait" value="20000" /><!-- 是否启用侦测查询。若开启,也必须使用一个可执行的 SQL 语句设置 poolPingQuery 属性(最好是一个非常快的 SQL),默认值:false。 --><property name="poolPingEnabled" value="true" /><!-- 配置 poolPingQuery 的使用频度。这可以被设置成匹配具体的数据库连接超时时间,来避免不必要的侦测,默认值:0(即所有连接每一时刻都被侦测 — 当然仅当 poolPingEnabled 为 true 时适用) --><property name="poolPingConnectionsNotUsedFor" value="3600000" /> <!-- 发送到数据库的侦测查询,用来检验连接是否处在正常工作秩序中并准备接受请求。默认是“NO PING QUERY SET”,这会导致多数数据库驱动失败时带有一个恰当的错误消息。 --> <property name="poolPingQuery" value="select 1" /> </dataSource>
上面注意一个属性值,在任意时间可以存在的活动(也就是正在使用)连接数量
这个值我设置成了300是因为我查看了我的阿里云服务器最大连接数是600,但是本地安装的MySQL我看了下my.ini 文件,默认最大连接数是341。你可以根据自己实际情况修改。
property name="poolMaximumActiveConnections" value="300" />
这里还要强调一点,这个值最好设置为0,否则会入坑。
<property name="poolMaximumIdleConnections" value="0" />
具体原因详情请移步:
使用Mybatis时请注意这两个参数,否则会让你的数据库连接爆掉
http://biancheng.dnbcw.net/mysql/420838.html
好了,坑总结完了。
现在献上自己的mybatis3 配置模板文件:
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd" ><configuration> <!-- Settings 必须放到最上面 --> <settings> <!-- 该配置影响的所有映射器中配置的缓存的全局开关。默认true --> <setting name="cacheEnabled" value="false" /> <!-- MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。 默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession 的不同调用将不会共享数据。 --> <setting name="localCacheScope" value="STATEMENT" /> <!-- 当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。 --> <setting name="jdbcTypeForNull" value="NULL" /> <!-- MyBatis内置的日志工厂提供日志功能,具体的日志实现有以下几种工具 SLF4J Apache Commons Logging Log4j 2 Log4j JDK logging 在诸如 WebSphere的环境中——WebSphere提供了Commons Logging的私有实现,你的Log4J配置将被忽略。 因Commons Logging已经存 在了,按照优先级顺序,Log4J自然就被忽略了 如果你的应用部署在一个包含Commons Logging的环境, 而你又想用其他的日志框架, 你可以通过在MyBatis的配置文件MyBatis-config.xml里面添加一项setting(配置)来选择一个不同的日志实现。 可选值:SLF4J、LOG4J、LOG4J2、JDK_LOGGING、COMMONS_LOGGING、STDOUT_LOGGING、NO_LOGGING --> <setting name="logImpl" value="LOG4J2" /> </settings> <!-- 设置数据库连接环境 default 数据库连接环境开关 development 本地环境 Product_Intranet 内网环境 --> <environments default="development"> <environment id="development"> <!-- 使用JDBC事务管理 --> <transactionManager type="JDBC" /> <!-- 配置数据库连接池 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://your ip:3306/your_db_name" /> <property name="username" value="root" /> <property name="password" value="test" /> <!-- 数据库连接池配置 --> <!-- 在任意时间可以存在的活动(也就是正在使用)连接数量,默认值:10 --> <property name="poolMaximumActiveConnections" value="300" /> <!-- 任意时间可能存在的空闲连接数 默认是5,最好设置为0,否则可能会崩溃掉 --> <property name="poolMaximumIdleConnections" value="0" /> <!-- 在被强制返回之前,池中连接被检出(checked out)时间,默认值:20000 毫秒(即 20 秒) --> <property name="poolMaximumCheckoutTime" value="20000" /> <!-- 这是一个底层设置,如果获取连接花费的相当长的时间,它会给连接池打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直安静的失败),默认值:20000 毫秒(即 20 秒)。 --> <property name="poolTimeToWait" value="20000" /> <!-- 是否启用侦测查询。若开启,也必须使用一个可执行的 SQL 语句设置 poolPingQuery 属性(最好是一个非常快的 SQL),默认值:false。 --> <property name="poolPingEnabled" value="true" /> <!-- 配置 poolPingQuery 的使用频度。这可以被设置成匹配具体的数据库连接超时时间,来避免不必要的侦测,默认值:0(即所有连接每一时刻都被侦测 — 当然仅当 poolPingEnabled 为 true 时适用) --> <property name="poolPingConnectionsNotUsedFor" value="3600000" /> <!-- 发送到数据库的侦测查询,用来检验连接是否处在正常工作秩序中并准备接受请求。默认是“NO PING QUERY SET”,这会导致多数数据库驱动失败时带有一个恰当的错误消息。 --> <property name="poolPingQuery" value="select 1" /> </dataSource> </environment> <!-- 上线状态内网版 --> <environment id="Product_Intranet"> <!-- 使用JDBC事务管理 --> <transactionManager type="JDBC" /> <!-- 配置数据库连接池 --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://your ip:3306/your_db_name" /> <property name="username" value="root" /> <property name="password" value="test" /> <!-- 数据库连接池配置 --> <!-- 在任意时间可以存在的活动(也就是正在使用)连接数量,默认值:10 --> <property name="poolMaximumActiveConnections" value="300" /> <!-- 任意时间可能存在的空闲连接数 默认是5,最好设置为0,否则可能会崩溃掉 --> <property name="poolMaximumIdleConnections" value="0" /> <!-- 在被强制返回之前,池中连接被检出(checked out)时间,默认值:20000 毫秒(即 20 秒) --> <property name="poolMaximumCheckoutTime" value="20000" /> <!-- 这是一个底层设置,如果获取连接花费的相当长的时间,它会给连接池打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直安静的失败),默认值:20000 毫秒(即 20 秒)。 --> <property name="poolTimeToWait" value="20000" /> <!-- 是否启用侦测查询。若开启,也必须使用一个可执行的 SQL 语句设置 poolPingQuery 属性(最好是一个非常快的 SQL),默认值:false。 --> <property name="poolPingEnabled" value="true" /> <!-- 配置 poolPingQuery 的使用频度。这可以被设置成匹配具体的数据库连接超时时间,来避免不必要的侦测,默认值:0(即所有连接每一时刻都被侦测 — 当然仅当 poolPingEnabled 为 true 时适用) --> <property name="poolPingConnectionsNotUsedFor" value="3600000" /> <!-- 发送到数据库的侦测查询,用来检验连接是否处在正常工作秩序中并准备接受请求。默认是“NO PING QUERY SET”,这会导致多数数据库驱动失败时带有一个恰当的错误消息。 --> <property name="poolPingQuery" value="select 1" /> </dataSource> </environment> </environments> <!-- 所有数据库语句映射表文件必须在这里注册 --> <mappers> <!-- 管理员表 --> <mapper resource="xingyun/dao/mapper/ManagerMapper.xml" /> </mappers></configuration>
第四坑:代码错误导致的缓存
忘了之前在哪里复制的这段MyBatis数据库连接工具类,今天发现这么写是有问题的,这样做会导致查询的结果不是数据库最新,而是缓存中的数据。
MybatisJDBCUtil.java错误代码贴上来:
import java.io.IOException;import java.io.InputStream;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;/** * MyBatis 获取数据库连接工具类 错误示范代码,切勿这么使用 * */public class MybatisJDBCUtil { private static final String resource = "mybatis-jdbc-config.xml";// SRC 根目录下必须有这个文件 private static InputStream inputStream; private static SqlSessionFactory sqlSessionFactory; static { try { inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { // TODO Auto-generated catch block System.err.println("can't find "+resource); } } private static final ThreadLocal<SqlSession> THREAD_LOCAL = new ThreadLocal<SqlSession>(); public static SqlSession currentSession() { SqlSession session = THREAD_LOCAL.get(); if (session == null) { session = sqlSessionFactory.openSession(); THREAD_LOCAL.set(session); } return session; } public static void closeSession() { SqlSession session = THREAD_LOCAL.get(); THREAD_LOCAL.set(null); if (session != null) { session.close(); } }}
下面附上MyBatis链接数据库工具类修正代码:
import java.io.IOException;import java.io.InputStream;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;/** * MyBatis 获取数据库连接工具类 */public class MybatisJDBCUtil { private static final String resource = "mybatis-jdbc-config.xml";// SRC // 根目录下必须有这个文件 private static InputStream inputStream; private static SqlSessionFactory sqlSessionFactory; private static SqlSession session; static { try { inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { // TODO Auto-generated catch block System.err.println("can't find " + resource); } } public static SqlSession currentSession() { session = sqlSessionFactory.openSession(); return session; } public static void closeSession() { if (session != null) { session.clearCache(); session.close(); } }}
- MyBatis 配置中那些值得注意的坑
- Block编程值得注意的那些事儿
- Block编程值得注意的那些事儿
- Block编程值得注意的那些事儿
- Block编程值得注意的那些事儿
- Block编程值得注意的那些事儿
- Block编程值得注意的那些事儿
- Block编程值得注意的那些事儿
- Block编程值得注意的那些事儿
- Block编程值得注意的那些事儿
- Block编程值得注意的那些事儿
- Block编程值得注意的那些事儿
- Block编程值得注意的那些事儿
- Block编程值得注意的那些事儿
- Java中Map值得注意的坑!
- [深入浅出Cocoa]Block编程值得注意的那些事儿
- [深入浅出Cocoa]Block编程值得注意的那些事儿
- [深入浅出Cocoa]Block编程值得注意的那些事儿
- java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
- leetCode刷题归纳-Divide and Conquer(241. Different Ways to Add Parentheses)
- JVM学习之类加载
- 欢迎使用CSDN-markdown编辑器
- 525. Contiguous Array Medium
- MyBatis 配置中那些值得注意的坑
- Android自定义View 一附<点,线,矩形,扇形和文字的简单用法>
- 泛型(二)->擦除&擦除带来的问题
- ubuntu 常见错误--Could not get lock /var/lib/dpkg/lock
- python 按普通字典排序(小写字母,排在大写字母前)
- Heater
- 大端模式和小端模式
- 系统项目集成管理
- Linux下stat命令的Access、Modify、Change时间的含义