一. Strus2+JSP+js 实现 .....................................................................................................................1
Struts2 的 token 使用 ................................................................................................................1
常见问题:................................................................................................................................2
二.Struts2+Hibernate 实现 .............................................................................................................4
1.系统介绍(在线购物/电子商务) .............................................................................................5
2.系统的架构设计.....................................................................................................................5
3. 数据库设计...........................................................................................................................6
4.搭建工程结构.........................................................................................................................6
利用 Myeclipse 生成 hbm 和 pojo............................................................................................7
Sh 常见问题: ........................................................................................................................11
使用@JSON(serialize=false)注解 将 get 方法注释掉,就是不让该类 序列化................15
MySQL 的 timeout 那点事 .....................................................................................................24
(2):How to decrease InnoDB shutdown times .................................................................26
MySQL INNODB 锁机制简单试验 ...............................................................................30
(三)当当 Struts2+hibernate3+spring ...............................................................................................34
相关问题:..............................................................................................................................34
关 于 :
异常的解决......................................................................................................................34
一.Strus2+JSP+js 实现
Struts2 的 token 使用
<s:token />标签防止重复提交,用法如下:
第一步:在表单中加入
<s:token />
<s:form action="helloworld_other" method="post" namespace="/test">
<s:textfield name=""/>
<s:token/><s:submit/> </s:form>
第二步:
<action name="helloworld_*" class="" method="{1}">
<interceptor-ref name="defaultStack"/>
<!-- 增加令牌拦截器 -->
<interceptor-ref name="token">
<!-- 哪些方法被令牌拦截器拦截 -->
<param name=“includeMethods">save</param>
</interceptor-ref>
<!-- 当表单重复提交转向的页面 -->
<result name="">/WEB-INF/page/</result> </action>
以上配置加入了“token” 拦截器和“”结果,因为“token”拦截器在会话的token与请求的token
不一致时,
将会直接返回 “”结果。
在debug状态,控制台出现下面信息,是因为Action中并没有和属性,
我们不用关心这个错误:
严重: ParametersInterceptor - [setParameters]:
Unexpected Exception caught setting '' on 'class xxx: Error
setting expression '' with value '[;@39f16f'
严重: ParametersInterceptor - [setParameters]: Unexpected Exception caught
setting ''
常见问题:
1. 自动增长的 id 值如何获取?
2.在设置配置文件时,因为默认的提交方式是转发,转发会携带所有的数据进入到下一个页
面,这样可能会造成重复匹配 action,这个可能是 struts2 标签的问题,很奇怪,解决方式是
在配置文件上面加上 type="redirect",让其提交方式变成重定向就可以了,但是不知道为什
么?
3.系统自动生成的 get/set 方法要注意,今天遇到的问题是分页时一个属性名为 cTwo,生成的
get 方法是 getcTwo,这样导致了当点击二级目录时,无法获取 cTwo,出现了空指针异常,这
个问题非常隐蔽,不是特别的好找,所以要非常注意。
4.关于 session 的问题(刷新页面的时候会出现问题,最后得出可能是缓存的问题)
1。问题一
从中,发送请求时,验证码这一项出现乱码。
$.post("", {
"code" : code
}, function(se) {
if (se) {
$("#number\\.info").html("验证码正确");
} else {
$("#number\\.info").html("验证码错误");
//$("#noSee").click();
}
});
解决方法:还改回用$.post方法。
$.ajax({
url:"",
async:false,
data:{"code":code},
success:function(se){
if (se) {
$("#number\\.info").html("验证码正确");
} else {
$("#number\\.info").html("验证码错误");
//$("#noSee").click();
}
}
});
2,类别流程:
main/->
根据$("#left").load("")解发aciton->
/main/->
<a href=' }&pid=${ }'>${ }</a>
->/main/
3,写好逻辑后,类别加载不上:
中:
<action name="login" class="">
<result name="success" type="redirect">
/main/
</result>
必须加上type="redirect",因为在main/中,如下代码:
<script type="text/javascript">
$(function(){
$("#left").load("");
});
</script>
必须在页面加载完成后,再执行。而在main/中有如下代码:
<s:action name="findnew" namespace="/main" executeResult="true">
</s:action>
在它执行完毕后,关闭了数据库Connection,页面加载后,用默认的转发是一个请求之
间,
所以就得不到数据。改为重定向,就可以解决了。
3 问题:引发的购物车不能删除或全删问题
必须通过引入,不能在迭代时删除,然后在循环外边删除。
不然有
public boolean delete(int pid) {
CartItem c = null;
for(CartItem cart : items){
if(().getId()==pid){
(cart);
(false);
//boolean b = (cart);// 动 态 删 除 有 异 常
ConcurrentModificationException
c = cart;//引入,能过从外部删除可以解决上句异常
}
}
(c);
return true;
}
4问题:!)Cookie,关闭浏览器后,再打开浏览器时,showCart()不能显示以前的定单,
而在中 确能显示以前放入Cookie里的信息。
2)删除后,定单转入恢复栏后,关闭浏览器后。恢复里的东西不能回显。
3)使用删除或恢复后出现 递增删除,递增恢复的情况
4)打开浏览器后,回显以前的数据,回显得到的确是上次更改前的定单数据。
解决:1)把订单中删除的和没删除的都放在一个集合里面。用isBuy这个属性来控制是否
是购买的
2)把service/impl/CartServiceImpl类中的analyze()和revert(String content)方
法
改成控制三个参数的字符串,分别为:定单ID,定单数量,是否购买
1或0;
3)在service/impl/CartServiceImpl类的delete(int pid)中不能有删除方法,不
然被删除的就不能通过
if (()) {
(().getId() + "," + () + ","+"1"+";");
}else{
(().getId() + "," + () + ","+"0"+";");
}
这里边的else{}了,会导致删除区不能回显。
4)递增问题是开始时定义两个集合,一个放购买的,一个放删除的,然后又加了
个isBuy的判断的放购买
的那个集合里存入了isBuy为false的元素,导致混乱。
5)定单数据问题:是因为在删除或更新数量时,没有及时更新Cookie里的数据,
我们在删除或更新等操作中,也要改Cookie的。不然更改的数据不能回显。
二.Struts2+Hibernate 实现
当当项目描述
数据库 导入过程
a.进入 mysql 控制台
database dangdang
dangdang
names utf8
D:\\
====================================
1.系统介绍(在线购物/电子商务)
模拟当当网部分主要功能.例如用户管理,产品浏览,购物车,创建订单等功能.
系统功能主要划分成以下模块
a.用户管理模块(3 天) user
用户登录,用户注册等功能
b.产品浏览模块(2 天) main
系统主界面,类别浏览界面,产品详细界面等
c.购物车模块( 天) cart
购买,修改,删除,恢复,查看列表,统计金额等
d.创建订单( 天) order
订单确认,填写送货地址,订单生成等
2.系统的架构设计
a.主要应用技术
Struts2,Hibernate,Ajax,jQuery 等
b.系统设计结构
主要基于 MVC,采用分层思想设计.
表现层:涉及 JSP,Ajax,jQuery,标签和 EL 表达式等技术
控制层:主要使用 Struts2 控制器
(复杂业务)业务层:主要使用 JavaBean.例如 Service 组件
数据访问层:主要使用 JavaBean,例如 DAO 组件,涉及 Hibernate 技术
3.数据库设计
1)d_user 用户信息表
存储用户的基本信息.与用户登录,用户注册功能相关
2)d_receive_address 用户地址信息表
存储用户使用过的地址信息.与填写送货地址功能相关
3)d_category 产品类别信息表
存储产品的类别信息.与主界面类别菜单功能相关
4)d_product 产品基本信息表
存储了各类型产品的基本共通信息.
5)d_book 图书信息表
存储了图书特有的信息.
6)d_category_product 产品类别和产品对应关系表
存储了某个类别包含了哪个商品的关系信息.
7)d_order 产品订单信息表
存储了订单的基本信息.
8)d_item 订单明细表
存储了某个订单所购买的产品信息.
4.搭建工程结构
1)src 结构
: Action 控制器组件
:用户模块 Action
:购物车模块 Action
:产品浏览模块 Action
:订单模块 Action
: Service 业务组件
: DAO 业务组件
: 与数据库对应的实体类
: 实体类映射文件
: 工具类
//:
//:
2)配置文件
: /WebRoot/WEB-INFO
: /src
: 用户模块相关配置
: 购物车模块相关配置
: 产品浏览模块相关配置
: 订单模块相关配置
3)WebRoot 结构
/user : 用户模块相关 JSP
/main : 产品浏览模块相关 JSP
/cart : 购物车模块相关 JSP
/order : 订单模块相关 JSP
/common : 共通 JSP,页眉页脚等
/images : 界面图片
/css : 样式文件
/js : js 脚本文件
/productImages : 产品图片
4) 工程搭建步骤
a.新建一个 Web 项目工程
b.引入需要开发包
struts2,hibernate,
c.添加配置文件
,struts2 配置,
Hibernate 配置:,HibernateUtil,POJO,
d.添加 JSP
e.划分 src 包结构
利用 Myeclipse 生成 hbm 和 pojo
1.进入 DB Browser 建立一个 dang 连接,连接到 dangdang 库
2.新建一个 web 工程,工程右键-->Myeclipse-->Add Hibernate Capbilities
按照提示,一步一步添加 Hibernate 框架 jar,,hibernate 工具类.
3.进入 DB Browser,选中要反向生成的数据表.
右键-->Hibernate reverse engine..
按照提示,一步一步添加 hbm,pojo,type-mapping,指定实体类名等.
4.将生成的 hibernate 元素,复制到 dang 工程中.
5.启动 Tomcat 访问页面,如果成功表明 struts 配置正确.
6.编写 Hibernate 测试类,如果成功,表明 hibernate 相关文件正确.
用户管理模块==================
1)用户注册功能
用户输入表单项,表单数据通过检查后,将数据写入到数据表 d_user,之后进入邮箱验证
页面.
a.客户端处理(负责表单格式检查)
Email 地址:非空(js),格式(js),唯一性(ajax)
昵称:非空,4-20 个字符(中文算 2 个)
密码:非空,6-20 个字符
确认密码:非空,与密码一致性
验证码:非空(js),正确性(ajax)
通过以上格式检查,才允许提交给服务器处理.
b.服务器端处理
密码进行加密处理
将表单信息写入 d_user 表
生成邮箱验证码,给用户发送
-------------------------------------------
先了解需求,然后了解相关数据表结构,之后开始编写程序.
---开始编写 DAO,根据需求定义接口方法,然后编写实现类
---开始编写 Action,定义属性和业务方法
---在相应模块的 struts 配置文件中定义 Action
---RegisterAction---->UserService--->UserDAO-->d_user
==============================================
2)邮箱验证
表单数据通过格式检查,采用 ajax 方式验证是否正确.
如果正确进入 ,不正确在 提示错误
a.客户端处理
验证码:非空,正确性(ajax)
b.服务器处理
去 d_user 中检查验证码是否正确.
验证码正确将 d_user 的 is_email_verify 字段更新为 Y.
Action 为 ajax 请求返回一个 boolean 结果(json)
3)用户登录
表单数据通过格式检查,进入服务器处理,
用户名和密码不正确返回
邮箱未通过验证,返回
登录成功进入/main/
a.客户端处理
Email : 非空,格式
密码 : 非空
b.服务器处理
检查 email 和密码是否正确
检查邮箱是否通过验证
更新 d_user 中 last_login_time 和 last_login_ip 字段信息
将用户信息写入 session
==================================================
1.验证码部分的实现
图片验证码显示:
--->ImageAction--->Result(stream)将图片属性输出
图片验证码验证:
ajax--->ValidImageAction(与 session 中的 code 比较)
--->json 方式输出一个 ok 结果--->客户端回调函数显示提示信息
2.采用拦截器实现事务管理和 Session 关闭(OpenSessionInView 模式)
提示:启用拦截器后,将 DAO 中的事务和 session 关闭代码删除
实现思想
1)最新上架图书实现
---->NewsAction(获取最新上架图书信息)--->
a.根据需求找到涉及的数据表,了解数据表结构
b.根据需求了解对数据表做什么操作,编写 DAO 实现
c.编写 Action 实现
d.编写 JSP 标签
e.输入 action 请求测试
f.将 响应内容引入到 中
利用 ajax 方式引入
利用<s:action>标签引入
2)编辑推荐实现 (d_product,d_book)
系统随机取两个产品显示.
可以采用下面特殊的 sql 完成,需要用 hibernate SQLQuery 执行 sql
select *
from d_product dp
join d_book db on(=)
order by rand() limit 0,2;
3)分类浏览实现 (d_category)
--->CategoryAction(获取类别数据)-->
将类别信息取出以父子关系格式显示页面
4)热销图书实现 (d_item,d_product)
根据订单销量排序,显示销量最多的前 8 个
根据 d_item 中的 product_num 统计(按 product_id 分组)进行排序,
获取销量最多的前 8 个.因为页面需要 d_product,因此需要 d_item
关联到 d_product.
from item join product(基于 many-to-one 关系)
from product join item(基于 one-to-many 关系)
-----------sql-------------
select p.*
from d_item i join d_product p on(_id=)
group by
order by sum(_num) desc
limit 0,3;
-------------hql---------------
select p
from Item i join p
group by
order by sum() desc;
5)新书热卖榜
将近一个月内销量最多的前 10 个取出显示.
(在 4 热销图书基础上,追加一个时间条件)
where addTime>?
(基于 Calendar 计算当前时间往前推一个月,然后给?号传入)
Category (c1, id)--------------------------->Category (c2,parent_id)
Set<Catetory> sublist;---->one-to-many---->Category
<set name="sublist">
<key column="parent_id"/>
<one-to-many class=""></one-to-many>
</set>
<list name="sublist">
<key column="parent_id"/>
<list-index column="turn" base=""/>
<one-to-many class=""></one-to-many>
</list>
User-------------------->ReceiveAddress
Set<ReceiveAddress> addresses;--->one-to-many--->ReceiveAddress
<set name="addresses">
<key column="user_id"/>
<one-to-many class=""></one-to-many>
</set>
==================分类浏览界面实现===================
------->BookListAction(获取页面数据)------>
BookListAction 需要获取以下数据:
用户单击类别的同级并包含产品数量.(d_category)
用户单击类别所包含的产品图书信息.(d_product,d_book)
==================================
数据库关系映射已添加如下:
Book 到 Product 追加了继承关系映射<joined-subclass>
Category 到 Product 追加了多对多关系映射<many-to-many>
Category 到 Category 追加了一对多关系映射<one-to-many>
=========购物车模块的实现================
1.根据购物车列表条目编写 CartItem
2.根据购物车功能编写 CartService 接口及实现类 Cart
(以上过程可参考原 shoppingcart 示例)
3.以购买为例,编写 Action 和 action 配置
(ajax)--->BuyAction--->Cart---->DAO--->d_product
4.编写 JSP 端的标签和 js 脚本
=========创建订单模块的实现===========
1.填写送货地址页面
1)用户填写送货地址信息后,当单击"下一步"按钮执行下面处理
a.先向 d_order 表写入一条记录.
b.然后向 d_item 表写入若干条记录(购物车有多少个购买的 Item 对象)
c.如果选择地址项为"填写新地址",将表单信息,
还要向 d_receive_address 表写入一份.
d.清空购物车信息
2)当用户选择地址下拉单选项时,执行下面处理
a.采用 ajax 方式根据选项去 d_receive_address 表查找以前用过的地址,
将地址信息以 json 格式返回
b.将地址信息填充到表单中各个输入框中.
c.如果选择的是"填写新地址",将表单各输入框清空
=============登录检查问题===============
编写一个登录检查的拦截器.(建议采用拦截器实现)
也可以在 Action 中添加登录检查代码.
Sh 常见问题:
一.:
在做地址回显时,返回的是json类型的对象,xml如下:
<action name="optionCart" class="">
<result type="json">
<param name="root">order</param>
</result>
</action>
在jsp中:
选择地址:
<select id="address">
<option value="0">填写新地址</option>
<s:iterator value="orders">
<option value="${id }">${fullAddress }</option>
</s:iterator>
</select>
Js如下:
$(function() {
$("#address").change(function() {
var id = $(this).val();
$.post("optionCart", {
"id" : id
}, function(data) {
var aa = data;
alert();
//alert();
});
});
});
报错信息如下:
:
at (:243)
at (:165)
at (:131)
at (:99)
at (:112)
at (:198)
at (:362)
(:266)
问题原因:是因为 hibernate 的延迟加载的原因,当你把对象转变成 json 时,session 已经被关闭
了。
解决方案:仿照 Spring 的 OpenSessionInView 机制,写自己的 OpenSessionInView 类,代码如下:
类:
package ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
/* * Hibernate 的 OpenSessionInView 过滤器,可以实现在页面中 Session 依旧不关闭,解决懒加载带来的副
作用,可以随意使用懒加载,提升系统效率
* * @author * */
public class HibernateSessionRequestFilter implements Filter {
private SessionFactory sf;
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
try {
// 开启 Session 和 Transcation,在 Hibernate 查询中需要用 getCurrentSession 获取当前
Session
().beginTransaction();
// 放行 (request, response);
// Session 提交,getCurrentSession 获取的 Session 会在提交之后自动关闭
().getTransaction().commit();
} catch (StaleObjectStateException staleEx) {
throw staleEx;
} catch (Throwable ex) {
// Rollback only
();
try { // 如果 Transcation 依旧存在,回滚
if (().getTransaction().isActive()) {
().getTransaction().rollback();
}
} catch (Throwable rbEx) {
();
}
// Let others handle it... maybe another interceptor for exceptions?
throw new ServletException(ex);
}
}
public void init(FilterConfig filterConfig) throws ServletException {
// sessionFactory, 可以通过自己的代码获取此值
sf = ;
}
public void destroy() {
}
}
SessionUtil 类的代码如下:
import ;
import ;
public class SessionUtil {
public static SessionFactory sessionFactory;
public SessionUtil() {
sessionFactory = ();
}
public Session getSession(){
return ();
}
}
在 里添加拦截器配置,代码如下:
<filter>
<filter-name>HibernateSessionInView</filter-name>
<filter-class></filter-class>
<init-param>
<param-name>singleSession</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>HibernateSessionInView</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
最后,测试正常了。问题解决了。不过,解决后,自己为了做总结,发现原来错误的情况下也正常了,不
管怎么测试都可以出来,真奇怪。从正常到不正常,调试好正常了。没改过的错误代码也正常了。
参考资料:
(一) : 由于对象里配置了延迟加载, 你在将对象转换成
json 的时候,hibernate session 已经关闭了。
你可以采用 open session in view 这中方式来配置 session 的 开关
(二) 这个错误是因为我的 Service 层在注入 Action 的时候让自动生成了 Get、Set 方法,
问题就出在 Get 方法上。返回的 JSON 对象也将这个 Get 方法当作类实体的属性来返回。
就会报错::
:
(:243)
(:165)
(:131)
(:99)
(:112)
(:198)
(
a:362)
(:266)
…
最后将这个 Get 方法去掉,OK 运行正常。 折腾了我半天 记录下
(三)package 继承 json-default。 action 结果类型为 json。
在 action 中的方法有以 get 开头的非 get/set 方法的缘故:
有两种解决方案:
1。把 getxxx()方法名改掉;
2。在 getxxx()方法前面用注释@JSON(serialize=false)
(四):使用 Maven 管理依赖关系:
为 Struts2添加 json-plugin
<dependency>
<groupId></groupId>
<artifactId>struts2-json-plugin</artifactId>
<version></version>
</dependency>
在 里添加
<interceptor name="json"
class="" />
<result-types>
<result-type name="json" class="" />
</result-types>
使用时:
<action name="jsontable" class="">
<interceptor-ref name="defaultStack" />
<result name="success" type="json"></result>
<result name="input">/WEB-INF/jsp/</result>
</action>
不过当有 Spring 的 bean 在 Action 内部时,要非常小心处理一个问题:
在 action 里面不能包含有接口的 get 方法
否则会出现下面的错误:
:
: Class can not access a
member of class
$PoolGuardConnectionWrapper with
modifiers "public"
…
还可以如下:
使用@JSON(serialize=false)注解 将 get 方法注释掉,就是不
让该类 序列化
(二),注册页面,注册页面,可以正常注册,注册后的用户也能正常登陆,也没有错误提示,
只是当查询数据库表时,发现 d_user 里没有插入的记录,但是控制台已经
执行了插入语句啊。插入语句如下:
开启事务
Hibernate:
insert
into
_user
(email, nickname, password, user_integral, is_email_verify, email_verify_code, last_login_time,
last_login_ip)
values
(?, ?, ?, ?, ?, ?, ?, ?)
??????????????
事务结束
开启事务
事务结束
开启事务
事务结束
开启事务
Hibernate:
update
d_user
set
is_email_verify=?
where
email_verify_code=?
事务结束
当手动在数据库里执行插入时,出错:
mysql> insertintod_user(email,nickname,password) values('jiadp@',
'jiapd','123456');
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
同样,当我在程序里:更改以下代码时:
public void save(User user) throws Exception {
(getSession().getFlushMode());
getSession().setFlushMode();
getSession().save(user);
}
得到的错误同上:
开启事务
AUTO
Hibernate:
insert
into
_user
(email, nickname, password, user_integral, is_email_verify, email_verify_code, last_login_time,
last_login_ip)
values
(?, ?, ?, ?, ?, ?, ?, ?)
ERROR - Lock wait timeout exceeded; try restarting transaction
log4j:ERROR No output stream or file set for the appender named [appender2].
: could not insert: []
当程序代码改为如下:
public void save(User user) throws Exception {
(getSession().getFlushMode());
getSession().save(user);
getSession().flush();
}
错误同样,如下:
ERROR - Lock wait timeout exceeded; try restarting transaction
log4j:ERROR No output stream or file set for the appender named [appender2].
: could not insert: [] at
(:103)
原因分析:
解决方案:
第一种方案:在中加入事务配置:
<property name="">true</property>
同时在执行插入时语句如下:
public void save(User user) throws Exception {
(getSession().getFlushMode());
getSession().save(user);
getSession().flush();
}
就可以了。
学生自己解决方案:
把建表语句时的:ENGINE=InnoDB DEFAULT CHARSET=utf8;去掉
后,重新建表就可以了。
参考资料:
(一):如:
+hibernate 的 demo 出现了不能插入到数据库的问题。Mysql:
测试方法:
Session session = getSession();//取得 session
Client client = new Client();
("client");
(client); // 保存
();
当不加入事务的时候执行,在控制台打印 sql 语句:
Hibernate: insert into (clientName) values (?)
问题1:
但是查询数据库中并没有添加记录?这是为什么?
但是我用 sql 手动添加数据时候,发现 clientId 已经自增了,这又是为什么?
测试方法:
Session session = getSession();
tx = ();
Client client = new Client();
("client");
(client);
();
();
当加入事务的时候,数据插入没有问题,数据库中也可以查询到。
问题2:
session 的 sava 方法必须加入事务才能成功提交吗?
附:数据库
问题补充:
(());打印结果为 AUTO,没有设置 FlushModel,默认就为 AUTO,同
时我调用 ()同样不能持久到数据库。
但是我用 sql 手动添加数据时候,发现 clientId 已经自增了,这又是为什么?
问题补充:
谢谢你的提示,数据库的 autocommit=1;
查询了 hibernate 官方指南,发现 hibernate 对自动提交默认为 false,必须加入事务手动提交,也可以在
hibernate 配置文件钟加 入属性 并设置为 true(不推荐这样),这样不加入事物也可
以自动提交,在没有设置改属性之前,如果不加入事 物,即使调用 (),数据也不能插入数据库
;但还有问题:
为 什 么 数 据 库 中 没 有 插 入 数 据 , 自 增 变 量 的 值 却 自 增 了 ; 也 就 是 当 我 在 不 加 入 事 务 和 不 设 置
属性的情况下调用 save()方法,数据库没有插入数据,但是我数据库钟设置为
auto_increment 的字段 id 的值却自增了,因为当我手动插入数据发现 id 值已经 是2了?
在这里 对于自动增长的问题 我来稍微的分析一下
首先稍微解释一下事务 对于事务来说 事务本省就是数据库的特有名词.当我们在执行一个插入操作的时候
其实数据库已经将这个数据保存起来了,只是没有显示到列表中,当我们如果执行事务去提交的话 他就把
这条数据放在表中,然而如果我们没有提交数据库就会删除这条数据 那么这个自动增长的列就自然会留下
来了。
参考二:
hibernate MySQL 无法正确插入数据
核心提示:摘自网上的一段解决办法。
原文: 一起 jquery,17jquery
下面是插入数据部分的程序:
public static void main(String[] args) {
User myuser= new User();
("new name2");
("33333");
("33333");
UserDAO dao = new UserDAO();
Transaction tran=().beginTransaction();
(myuser);
}
改正方法:
程序错误,将程序改为:
public static void main(String[] args) {
User myuser= new User();
("new name3");
("33333");
("33333");
UserDAO dao = new UserDAO();
Transaction tran=().beginTransaction();
();
(myuser);
();
}
关于此类问题,我在网上看到了一些其他解法,虽然我没有用上,但仍然给我一些启发,现将其他解法分
享如下: 一起 jquery,17jquery
1.背景
之前从没用过 hibernate,因此在网上搜了一下 hibernate 快速入门方面的信息,最后我按照《Myeclipse
Hibernate 快速入门 中文版》(CSDN,百度文库都有)一文开始了我的 hibernate 之旅(为项目做技术准
备)。
下面是在学习使用时用到的三个开发工具(Myeclipse , Mysql , SQL-Front)及其版本说明:
Myeclipse 版本为(没用最新的 ,这是由于之前组里的项目都是在 中开发的,
并且本项目是与 其它人合作完成的,为了防止可能由于开发环境的不一致而引起的问题,我们统一使用
,所以我就在 环境下学 习使用 hibernate 了)。
Mysql 使用的是版本。Mysql 安装完后,需要手动进行配置,其中有一项是“please select the database
usage”,我在这里选择的是“Muitifunctional Database”(如下图所示)。这里其实选则的是使用何种类型的
数据库(InnoDB 还是 MyISAM),如果选第三个,就不能用 InnoDB 类型的 数据库了,这个在每一个选
项的说明中可以看到。
一起 jquery,17jquery
内容来自17jquery
为了方便 mysql 的使用,又安装了图形化界面的 SQL-Front,版本是。
2.遇到的问题
我用 SQL-Front 在数据库中建了一简单的表用于学习,等同的 SQL 语句如下:
“author”表有两个字段,一个是主键“Id”,一个是“name”。需要说明的是 SQL-Front 在建表的时候默认数据
库类型为 InnoDB。
针对“author”表,按照《Myeclipse Hibernate 快速入门 中文版》一文的说明操作完成后,写了一段简单的
测试代码:
即插如一条 name 字段为“author”的数据,但是发现执行完后数据根本就没有插入到数据库中。后来在网上
搜了一下,有人给出了解决办法,即使用事务来解决,修改后的代码如下:
数 据插入的问题是解决了,但是发现插入数据后,Id 已经在插入前自动增加了(不是从1开始了),也就
是说之前的测试虽然数据看似没有插入数据库,但是实际效 果却跟插入了数据库一样(要不然 Id 不会自
动增加),这又是为什么?在网上搜了一下,结合自己的理解,我分析了一下原因。
3.原因
上述问题的原因的本质我认为在于使用的数据库类型。
我使用的数据库类型是“InnoDB”,这是一个支持事务的数据库类型,这种数据库你无论什么操作,最后如
果你不“commit”的话,等于啥也没干(这 其中的道理在网上搜一下对数据库中事务的简单介绍应该不难理
解)。虽然通过 save 方法可以将 sql 语句发送到数据库让其执行(备注:并不是所有的 save 方法都会将 sql
语句发送到数据库,当主键生成策略为 native 的时候会发送到数据库,比如“author”的主键 Id,其生成策略
就为 native,不过可以通过 ().flush() 强行将 sql 语句发送到数据库。这些我 也只是知道一
点皮毛,有时间还需要深入了解),数据库也确实执行了(分配了 Id,并且将 Id 自动加1),但是这个执
行的结果只是临时的,如果不 “commit”的话,随着会话 session 的结束(即上述代码中 ().close()
语句),这个临时的执行结果也就没 了,直接的体现就是数据没有最终插入数据库。
通过 SQL-Front 可以很好的观察到这一过程(针对未引入事务的那段代码),首先在 ().Close()
处 设置断点,然后用 SQL-Front 打开这个表,并设置 SQL-Front 与 mysql 的会话隔离级别为(Read
Uncommitted,默认的级别为 Repeatable Read,这个网上也有很多介绍的,也不多说了),然后执行测试代
码,执行到断点处后,也即刚刚执行完 (author) 而还没有关闭本次会话,通过 SQL-Front 会发现,
这个数据插入到了表中(当然是“临时”插入数据,如果会话隔离级别不是 Read Uncommitted 的话是看不到
这条插入的数据的),继续执行 ().close() 后,通过 SQL-Front 刷新“author”表中的数据,会
发现刚刚插入的那条数据又消失了。 一起 jquery,17jquery
不过这其中有一个比较特殊的地方,那就是 Id 这个自段了。这个字段是“author”表的主键,并且它的值是
数据库自己产生的,在插入数据的时候不需要指 定这个字段的值。这个字段的特殊之处在于你在插入数据
的时候,无论最后是否“commit”,这个字段的值都会自动加1供下一次插入数据时使用,不会说由 于本次
会话没有“commit”,而在会话结束时自动减1恢复到原来的值。
这一点我觉得应该是出于并发的考虑(没有查阅相关资料,只是提出我自己的猜测)。假设有三个会话 A
和 B,都要向“author”表中插入数据(假设表中没 有数据,Id 从1开始),A 首先调用了 save 方法,数据
库为 A 插入的数据分配的 Id 是1,然后“author”表将 Id 自动加1并保存,在 A 未 “commit”之前,B 也调用
了 save 方法,自然数据库为 B 插入的数据分配的 Id 是2(不会是1,如果是1,A 和 B 将要提交的数据主
键 Id 值就冲突 了,会造成 A 和 B 谁后“commit”数据谁失败,数据库就无法并发了),“author”表将 Id 字
段再次加1后保存(此时为下一组数据使用的 Id 值为 3),假设 B 首先“commit”了数据,即“author”表中有
了 Id 字段值为2的数据,而 A 最终没有“commit”数据,如果此时 “author”表的字段自动减1,可以看到,下
一次数据插入分配的 Id 字段值就会是2,和现有的数据发成了主键冲突。因此,对于“author”表中 Id 这个
字段,无论某个插入操作是否最终“commit”,只要调用了 save 方法,Id 字段就会自加1。这也能解释之前
遇到的那个问题,即数据没有插 入,Id 字段却自动增加了。
4.解决方法
总共有两种解决方法:
第一种 : 可以考虑使用“MyISAM”类型的数据库,这种类型的数据库不支持事务,因此在调用 save 方法
的时候(注意,如果主键生成策略不是 native 的,必须在 save 后调用 ().flush() 方 法,即强
行将 sql 语句发送到数据库,否则一样没有插入数据),数据就已经最终插入到数据库里了(注意,这是
最终结果,不是临时结果,这和使用 “InnoDB”类型数据库时“commit”的效果是一样的)。当然了,直接使
用事务机制(就像上面那段修改后的代码一样)也是可以的 (“MyISAM”类型的数据库虽然不支持事务,
但是并不代表不能用 hibernate 里的事务机制,这两个概念还不太一样。当主键生成策略不是 native 的时候
,使用事务机制还省的调用 ().flush() 方法了)。mysql 支持“MyISAM”类型的数据库,可以
在 SQL-Front 中直接将“InnoDB”类型的数据库转为“MyISAM”类型的数据库(建议这么做的时候 小心,因
为看到网上有人说这么做可能会产生问题,不过我转换的时候倒是没碰到什么问题,也可能是我的“author”
表简单的缘故),也可在建表的时候直 接指定类型为“MyISAM”。关于“MyISAM”类型的数据库的更多信
息(比如相对于“InnoDB”类型数据库有什么优缺点)网上也有很多介绍,就 不在这里罗嗦了。
第二种: 还是使用“InnoDB”类型的数据库。这时可以通过两种途径解决:一是像上面那个修改后的代码一
样,加入事务机制,这是最保险的(也推荐使用);第二个途径就是在 hibernate 的配置文件中,加入自动
提交的属性,如下图所示:
这个属性的作用是,一旦调用了 save 方法(和第一种解决方法一样,如果主键生成策略不是 native 的,必
须在 save 后调用 ().flush() 方法),hibernate 会自动帮你“commit”,在代码里不需要自己写
关于事务的那些代码(例如 commit 调用)。这么做的缺点网上也有很多说明,也不在这里多说了。
5.总结
由于我水平实在有限(大菜鸟一个啦),表达能力也不是很好,所以说了这么多也可能还没说明白,没说
透彻。不过我觉的对大家有用的一个结论就是,无论什么操作,都放在事务里提交,这样是最省事,也是
最保险的。
(二):分析
(三)ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
因为最近遇到一些超时的问题,正好就把所有的 timeout 参数都理一遍,首先数据库里查一下看有哪些超
时:
root@localhost : test 12:55:50> show global variables like "%timeout%";
+----------------------------+--------+
| Variable_name | Value |
+----------------------------+--------+
| connect_timeout | 10 |
| delayed_insert_timeout | 300 |
| innodb_lock_wait_timeout | 120 |
| innodb_rollback_on_timeout | ON |
| interactive_timeout | 172800 |
| net_read_timeout | 30 |
| net_write_timeout | 60 |
| slave_net_timeout | 3600 |
| table_lock_wait_timeout | 50 | # 这个参数已经没用了
| wait_timeout | 172800 |
+----------------------------+--------+
我们一个个来看
connect_timeout
手册描述:
解释:在获取链接时,等待握手的超时时间,只在登录时有效,登录成功这个参数就不管事了。主要
是为了防止网络不佳时应用重连导致连接数涨太快,一般默认即可。
delayed_insert_timeout
手册描述:
解释:这是为 MyISAM INSERT DELAY 设计的超时参数,在 INSERT DELAY 中止前等待 INSERT 语
句的时间。
innodb_lock_wait_timeout
解释:描述很长,简而言之,就是事务遇到锁等待时的 Query 超时时间。跟死锁不一样,InnoDB 一旦
检测到死锁立刻就会回滚代价小的那个事务,锁等待是没有死锁的情况下一个事务持有另一个事务需要的
锁资源,被回滚的肯定是请求锁的那个 Query。
今天导入数据的时候出现这样的问题了,傻乎乎的不明白是怎么一回事..百度跟 google 了半天都是解决
linux 下的..终于黄天不负有心人让我 google 到了解决办法..
This is my configuration file:
# Data node default setting.
[NDBD DEFAULT]
NoOfReplicas=2
DataMemory=400M
IndexMemory=50M
DiskPageBufferMemory=10024K
SharedGlobalMemory=80M
MaxNoOfConcurrentOperations=500000
MaxNoOfOrderedIndexes=512
TimeBetweenLocalCheckpoints=30
TransactionDeadLockDetectionTimeOut=10000
# TCP/IP options:
[TCP DEFAULT]
#portnumber=2202
SendBufferMemory=1024K
还有记下:
MySQL 官方手册介绍 影响到 InnoDB 关闭的参数有
innodb_fast_shutdown
如果你把这个参数设置为0,InnoDB 在关闭之前做一个完全净化和一个插入缓冲合并。这些操作要花几分
钟时间,在极端情况下要几个小时。
如果你设置这个参数为1,InnoDB 在关闭之时跳过这些操作。 默认值为1。
如果你设置这个值为2 (在 Netware 无此值), InnoDB 将刷新它的日志然后冷关机,仿佛 MySQL 崩溃一样。
已提交的事务不会被丢失,但在下一次启动之时会做一个崩溃恢复。
innodb_max_dirty_pages_pct
这是一个范围从0到100的整数。默认是90。InnoDB 中的主线程试着从缓冲池写页面,使得脏页(没有被写
的页面)的百分比不超过这个值。如果你有 SUPER 权限,这个百分比可以在服务器运行时按下面来改变:
SET GLOBAL innodb_max_dirty_pages_pct =value;
MySQL 的 timeout 那点事
网址:
因为最近遇到一些超时的问题,正好就把所有的 timeout 参数都理一遍,首先数据库里查一下看有哪些超时
:
root@localhost : test 12:55:50> show global variables like "%timeout%";
+----------------------------+--------+
| Variable_name | Value |
+----------------------------+--------+
| connect_timeout | 10 |
| delayed_insert_timeout | 300 |
| innodb_lock_wait_timeout | 120 |
| innodb_rollback_on_timeout | ON |
| interactive_timeout | 172800 |
| net_read_timeout | 30 |
| net_write_timeout | 60 |
| slave_net_timeout | 3600 |
| table_lock_wait_timeout | 50 | # 这个参数已经没用了
| wait_timeout | 172800 |
+----------------------------+--------+
我们一个个来看
1 connect_timeout
2 delayed_insert_timeout
3 innodb_lock_wait_timeout
4 innodb_rollback_on_timeout
5 interactive_timeout/wait_timeout
6 net_read_timeout / net_write_timeout
7 slave_net_timeout
connect_timeout
手册描述:
The number of seconds that the mysqld server waits for a connect packet before responding with Bad handshake.
The default value is 10 seconds as of MySQL and 5 seconds before that.
Increasing the connect_timeout value might help if clients frequently encounter errors of the form Lost connection
to MySQL server at ‘XXX’, system error: errno.
解释:在获取链接时,等待握手的超时时间,只在登录时有效,登录成功这个参数就不管事了。主要是为
了防止网络不佳时应用重连导致连接数涨太快,一般默认即可。
delayed_insert_timeout
手册描述:
How many seconds an INSERT DELAYED handler thread should wait for INSERT statements before
terminating.
解释:这是为 MyISAM INSERT DELAY 设计的超时参数,在 INSERT DELAY 中止前等待 INSERT 语句
的时间。
innodb_lock_wait_timeout
手册描述:
The timeout in seconds an InnoDB transaction may wait for a row lock before giving up. The default value is 50
seconds. A transaction that tries to access a row that is locked by another InnoDB transaction will hang for at most
this many seconds before issuing the following error:
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
When a lock wait timeout occurs, the current statement is not executed. The current transaction is not rolled back.
(To have the entire transaction roll back, start the server with the –innodb_rollback_on_timeout option, available
as of MySQL . See also Section , “InnoDB Error Handling”.)
innodb_lock_wait_timeout applies to InnoDB row locks only. A MySQL table lock does not happen inside
InnoDB and this timeout does not apply to waits for table locks.
InnoDB does detect transaction deadlocks in its own lock table immediately and rolls back one transaction. The
lock wait timeout value does not apply to such a wait.
For the built-in InnoDB, this variable can be set only at server startup. For InnoDB Plugin, it can be set at startup
or changed at runtime, and has both global and session values.
解释:描述很长,简而言之,就是事务遇到锁等待时的 Query 超时时间。跟死锁不一样,InnoDB 一旦检
测到死锁立刻就会回滚代价小的那个事务,锁等待是没有死锁的情况下一个事务持有另一个事务需要的锁
资源,被回滚的肯定是请求锁的那个 Query。
innodb_rollback_on_timeout
手册描述:
In MySQL , InnoDB rolls back only the last statement on a transaction timeout by default. If –
innodb_rollback_on_timeout is specified, a transaction timeout causes InnoDB to abort and roll back the entire
transaction (the same behavior as in MySQL ). This variable was added in MySQL .
解释:这个参数关闭或不存在的话遇到超时只回滚事务最后一个 Query,打开的话事务遇到超时就回滚整
个事务。
interactive_timeout/wait_timeout
手册描述:
The number of seconds the server waits for activity on an interactive connection before closing it. An interactive
client is defined as a client that uses the CLIENT_INTERACTIVE option to mysql_real_connect(). See also
解释:一个持续 SLEEP 状态的线程多久被关闭。线程每次被使用都会被唤醒为 acrivity 状态,执行完 Query
后成为 interactive 状态,重新开始计时。wait_timeout 不同在于只作用于 TCP/IP 和 Socket 链接的线程,
意义是一样的。
net_read_timeout / net_write_timeout
手册描述:
The number of seconds to wait for more data from a connection before aborting the read. Before MySQL ,
this timeout applies only to TCP/IP connections, not to connections made through Unix socket files, named pipes,
or shared memory. When the server is reading from the client, net_read_timeout is the timeout value controlling
when to abort. When the server is writing to the client, net_write_timeout is the timeout value controlling when to
abort. See also slave_net_timeout.
On Linux, the NO_ALARM build flag affects timeout behavior as indicated in the description of the
net_retry_count system variable.
解释:这个参数只对 TCP/IP 链接有效,分别是数据库等待接收客户端发送网络包和发送网络包给客户端
的超时时间,这是在 Activity 状态下的线程才有效的参数
slave_net_timeout
手册描述:
The number of seconds to wait for more data from the master before the slave considers the connection broken,
aborts the read, and tries to reconnect. The first retry occurs immediately after the timeout. The interval between
retries is controlled by the MASTER_CONNECT_RETRY option for the CHANGE MASTER TO statement or –
master-connect-retry option, and the number of reconnection attempts is limited by the –master-retry-count option.
The default is 3600 seconds (one hour).
解释:这是 Slave 判断主机是否挂掉的超时设置,在设定时间内依然没有获取到 Master 的回应就人为
Master 挂掉了
(2):How to decrease InnoDB shutdown times
Sometimes a MySQL server running InnoDB takes a long time to shut down. The usual culprit (根
本原因)is flushing dirty pages (刷新脏数据)from the buffer pool. These are pages that have been
modified(修正) in memory, but not on disk.
If you kill the server before it finishes this process, it will just go through the recovery phase(恢
复阶段) on startup, which can be even slower in stock InnoDB than the shutdown process, for a
variety of way to decrease the shutdown time is to pre-flush the dirty pages, like this:
Shell
mysql> set global innodb_max_dirty_pages_pct = 0;
Now run the following command:
Shell
$ mysqladmin ext -i10 | grep dirty
| Innodb_buffer_pool_pages_dirty | 1823484 |
| Innodb_buffer_pool_pages_dirty | 1821293 |
| Innodb_buffer_pool_pages_dirty | 1818938 |
And wait until it approaches zero. (If the server is being actively used, it won’t get to zero.)
Once it’s pretty (相当)low, you can perform(执行) the shutdown and there’ll be a lot less
unfinished work to do, so the server should shut down more quickly.
Mark Callaghansays: April 15, 2009 at 10:04 am
Baron – you can update this article to include a link to a Percona binary that makes this faster.
It is one thing to ask InnoDB to lower the percentage of dirty buffers, it is another thing for
InnoDB to do that on a busy server.
If writes are slow on your server, then you really need the Percona patches or features from the v3
Google patch to make the writing use the available IO capacity on a server. The patches to use
include innodb_io_capacity, more background IO threads and a few others.
Writes to files in the OS buffer cache are fast. Writes may be slow when:
* using innodb_flush_method=O_DIRECT
* disabling SATA writeback cache
* not using a HW RAID disk cache
* using NFS or some other remote storage service that doesn’t buffer writes in the OS buffer
cache
Kevin Burtonsays: April 15, 2009 at 10:45 pm
We made this a standard part of /etc/ stop.
It just sets this and waits for MySQL to finish writing and then allows the stop to happen.
The main problem is that the mysql control port is closed to there’s now way to figure out what
MySQL is doing while you’re waiting…
You mention Innodb. There’s also a very nasty option which can affect MyISAM users, especially
if you use MyISAM for datawarehouse issues. (smaller memory and disk footprint than
innnobase)
This is something taken from our wiki, and discovered after discussing in detail with the MySQL
support team.
delay_key_write=ON
This global configuration variable can be used (delay_key_writes=ALL) to stop writes from the
MySQL key buffer to disk. It’s only been used on slave servers, not the masters.
This option sounds great but DO NOT USE IT. It has a very nasty effect of leaving the key data
for MyISAM tables in memory and not written to disk. When you want to shutdown the server the
server is forced to do a FLUSH TABLES and this can take a long time. On the XXX servers
we’ve seen this take between 20 and 50 minutes.
NOTE: These are boxes running the MyISAM engine exclusively and having 32GB of RAM.
(key_buffer 12GB)
So something to remember if you have a server setup this way.
patsays:
April 16, 2009 at 4:47 pm
Is this really shutting down my server any faster in wall clock time?
Without setting the max_dirty_pages flag to zero, say it takes me 15 minutes to shut down.
If I do set it, doesn’t it just take me 14 minutes for dirty pages to drop to zero and 1 minute for the
shutdown?
Seems like it might make the shutdown *command* take less time, but the actual elapsed time
from the moment you decide to shut down the server to the time mysqld terminates isn’t
decreasing is it?
Kevin Burtonsays: April 16, 2009 at 5:14 pm
pat,
If you’re new to MySQL and your DB is taking 12 minutes to shutdown, and the port is closed,
one might assume that the DB is broken and kill -9 it..
Our script actually prints that it’s flushing the buffer pool and prints percentage until complete
numbers.
Baron Schwartzsays: April 16, 2009 at 7:39 pm
Pat,
If your server takes 15 minutes to shut down, you can keep the application online and responding
for some portion of that time, while dirty pages are flushed from the buffer pool. The alternative is
to take the app offline for the whole 15 minutes. The point is to reduce the amount of time that the
server is *actually* shutting down and restarting, by *preparing* it for shutdown.
Kevin, can you post your shutdown script? Maybe put it on your blog and link to it here? Maybe
contribute it to your favorite distro? It sounds useful.
Coolyousays: April 16, 2009 at 8:29 pm
Kevin, we were about to write one of these scripts ourselves until we realized that we may have an
issue with figuring out how far we are with the flushing. Could you please provide us all with the
script? It may prove very useful
Pat, the whole idea of this is to keep the application online for a longer period of time than having
MySQL refuse all connections for that 15 minutes.
However I have noticed that MySQL performance decreases dramatically when
innodb_max_dirty_pages_pct = 0 is in effect. That’s not unexpected considering that the dirty
pages are immediately flushed to disk. But those with a busy site may want to consider this
limitation because this option may even increase the time required to shut down because of the
increased load from the application itself and the increased time it takes for the application to
respond.
Kevin Burtonsays: April 17, 2009 at 9:49 am
Hey Baron….
Here’s the script we’re using:
If we were to write it again it would almost certainly be written in python.
Kevin
Kevin Burtonsays: April 17, 2009 at 9:51 am
Another note… we have three replicas of everything.
When we restart an InnoDB box it is taken out of production and does not serve requests.
Then we flush the innodb buffer pools, then restart it.
The script I linked to above is just added as a one liner to our /etc/ script…. if InnoDB
isn’t running on this box it isn’t run.
We have about 1/2 of our cluster on MyISAM without InnoDB enabled so this would break
otherwise.
Wagner Bianchisays: April 17, 2009 at 6:47 pm
This is a very good idea.
So nice.
Kayra Otanersays: May 14, 2009 at 9:16 am
Even after all the updating threads shut down, you’ll see Innodb_buffer_pool_pages_dirty count
approaching to 0 but still increasing sometimes. This is because of InnoDB merges, you can
observe this using ‘show engine innodb status\G’. Only when all the merges are completed
pages_dirty count will be 0 and stay at zero. To calculate how many merges still need to be done :
Under “INSERT BUFFER AND ADAPTIVE HASH INDEX” section difference between
‘Inserts’ and ‘merged recs’ will show how many to go. Example :
————————————-
INSERT BUFFER AND ADAPTIVE HASH INDEX
————————————-
Ibuf: size 4185, free list len 3748, seg size 7934,
65171060 inserts, 65171060 merged recs, 10552858 merges
Hash table size 7055701, used cells 32410, node heap has 33 buffer(s)
65171060 – 65171060 = 0
this means that Innodb_buffer_pool_pages_dirty should be 0 and stay at 0. Please note this
calculation works most of the time, but sometimes ‘inserts’ – ‘merged recs’ value goes negative
values.
Baron Schwartzsays: May 14, 2009 at 10:36 am
Kayra, it can become negative because the insert buffer survives after restart and merging can
continue after the server is started again. Peter tells me he has seen servers take weeks to catch up
in some cases!
kerja kerassays: October 18, 2009 at 8:39 pm
great tips, its very helpful. thanks for share
Coway Zhousays: September 10, 2010 at 10:17 am
I tried it once. But it never worked. I lost patient and did a kill -9. Of course, when the db was
started, it did long time in recovery. At least it showed some progress in recovery.
Wagner Bianchisays: September 10, 2010 at 12:02 pm
Take when issue a KILL -9 command against mysqld. If MySQL is answering any writes on any
MyISAM tables, you’ll see problems that would be repaired.
Wagner Bianchisays: September 10, 2010 at 12:02 pm
Sorry, *Take care
Andy Blylersays:
October 27, 2010 at 5:07 am
You can also execute the following SQL query to get the current count of the dirty pool pages,
instead of using mysqladmin:
show global status like ‘Innodb_buffer_pool_pages_dirty’;
sysadminsays: December 21, 2012 at 6:57 am
Unfortunately, setting innodb_max_dirty_pages_pct = 0 had no effect in my case:
[root@db12 ~]# mysqladmin ext -i10 | grep dirty
| Innodb_buffer_pool_pages_dirty | 2958 |
| Innodb_buffer_pool_pages_dirty | 2979 |
| Innodb_buffer_pool_pages_dirty | 2970 |
# at this moment dirty_pages_pct was set to zero
| Innodb_buffer_pool_pages_dirty | 3034 |
| Innodb_buffer_pool_pages_dirty | 3042 |
| Innodb_buffer_pool_pages_dirty | 3071 |
| Innodb_buffer_pool_pages_dirty | 3165 |
| Innodb_buffer_pool_pages_dirty | 3161 |
| Innodb_buffer_pool_pages_dirty | 3144 |
| Innodb_buffer_pool_pages_dirty | 3014 |
| Innodb_buffer_pool_pages_dirty | 3025 |
| Innodb_buffer_pool_pages_dirty | 3046 |
| Innodb_buffer_pool_pages_dirty | 2973 |
Strangely, but Innodb_buffer_pool_pages_dirty even increased instead of dropping to zero. Are
those values (several thousands) too small for this technique to work? innodb_buffer_pool_size is
25G, server has 32G, db size is near 20G (sql-dump). Even after few hours after setting
dirty_pages_pct to zero Innodb_buffer_pool_pages_dirty numbers still the same. And MySQL
also is using several Gigs of swap…
MySQL INNODB 锁机制简单试验
使用 mysql 连接 mysql 数据库,建两个会话(连接)。每个会话中都分别 set autocommit=0;
关闭自动提交。使用 INNODB 表做一下试验。
会话一:
mysql> desc test;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| a | int(11) | NO | PRI | | |
| b | varchar(10) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set ( sec)
mysql> set autocommit=0;
Query OK, 0 rows affected ( sec)
mysql> insert into test values(1,'abcde');
Query OK, 1 row affected ( sec)
会话二:
mysql> set autocommit=0;
Query OK, 0 rows affected ( sec)
mysql> select * from test;
Empty set ( sec)
mysql> delete from test where a=1;
这里被锁住了(会话一中 commit;或者 rollback;,会话二才会有响应)
过了一会儿,报错:
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
上述情况下,ORACLE 中不会被锁住。
下面是更加需要注意的:
会话一:
mysql> commit;
Query OK, 0 rows affected ( sec)
mysql> select * from test;
+---+-------+
| a | b |
+---+-------+
| 1 | abcde |
+---+-------+
1 row in set ( sec)
mysql> insert into test values(1,'abcde');
ERROR 1062 (23000): Duplicate entry '1' for key 1
会话二:
mysql> delete from test where a=1;
还是被锁住,过一会儿,则
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
我在两个会话中执行了 SET TRANSACTION ISOLATION LEVEL READ COMMITTED ;
结果仍然相同。
再做新的试验:
会话一:
mysql> create table testfk(a int, constraint fk_testfk foreign key(a) references test(a)) engine=innodb;
Query OK, 0 rows affected ( sec)
mysql> insert into testfk values(1);
Query OK, 1 row affected ( sec)
mysql> select * from test;
+---+-------+
| a | b |
+---+-------+
| 1 | abcde |
+---+-------+
1 row in set ( sec)
mysql> select * from testfk;
+------+
| a |
+------+
| 1 |
+------+
1 row in set ( sec)
mysql> commit;
Query OK, 0 rows affected ( sec)
mysql> update test set a=2 where a=1;
ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`test/testfk`,
CONSTRAINT `fk_testfk` FOREIGN KEY (`a`) REFERENCES `test` (`a`))
会话二:
mysql> update test set a=1 where a=1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
因此,在 mysql innodb 中使用事务,如果插入或者更新出错,一定要主动显式地执行 rollback,否则可能产
生不必要的锁而锁住其他的操作。
问题(三):在注册页面,当中加入如下控制时,不能进行json后台验证的数据返回,js代码如下:
//检查唯一性
$.post("validEmail",{"email":emailTxt},function(data){
//data是服务器返回的ok值
alert("123465");
if(data){
$("#email\\.info").html("<img src='../images/'></img>");
=true;
}else{
$("#email\\.info").html("Email地址已被占用");
}
});
也就是说发送 validEmail 请求,没有返回数据。原因分析,可以因为发送请求后,数据还没有返回时,session
就被关闭了。根据这个找了一个邮箱验证的类,最终发现他的 dao 代码中关闭了 session:
public User findByEmail(String email) throws Exception {
String hql="from User where email=?";
Query query = getSession().createQuery(hql);
(email);
(0,email);
User user =(User) ();
//closeSession();
return user;
}
有了事务控制,应该把 dao 层的事务控制都去掉,不然会出现很多不必要的问题。OK,解决。
(三)当当 Struts2+hibernate3+spring
相关问题:
关 于 :
异常的解决
此异常是我在用 SSH2技术写 OA 项目中,由前台发生的异常,一般浏览器还没发检查除错
误,只有用了火狐 F12才看到响应的结果。
错误发生在,当我登录成功后,点击“注销”后回到登陆页面,此时再次登录就报这个错误,
除非重启服务起,不然怎么也登录不上了。
先来搜索一下别人的方案:
错 误 :: :
: failed to lazily initialize a collection of role:
, no session
相信大家都知道是什么错,延迟加载的问题。
怎么解决?!
先说一下我尝试过的方法:
在 中加入代码:
Java 代码
<!-- 解决延迟加载的问题 -->
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class></filter-class>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
错误依然!
相关信息:jq 访问一个 action,action 的代码如下:在 action 断点是可以看到 livesourceList 有数据的。
Java 代码
public String execute() {
livesourceList=();
return SUCCESS;
}
代码如下:
Java 代码
<action name="allsource" class="" >
<result type="json" />
</action>
访问的时候就报错了。
以 上是别人的做法,经过自己思考,仍然无果,后来只得请来我的老师(真庆幸我还有老师)帮忙看一下
,老师一开始也是纠结在我的 struts2配置文件中的 action 及类中的方法,事实证明我的 struts2配置文件没
有错误,类方法也都正确。无奈又检查了下我的 spring 配置文件,哈哈,发现了错误:
<bean id="userAction" class="" parent="baseAction" scope="prototype"></bean>
<bean id="roleAction" class="" parent="baseAction" scope="prototype"></bean>
<bean id="rightAction" class="" parent="baseAction" scope="prototype"></bean>
<bean id="roleRightAction" class="" parent="baseAction"
scope="prototype"></bean>
红色为老师添加的错误,老师一说“作用域没改,不然默认为 singleton,当"注销"后,仅有的一个 session 没
了,因此……”,我嗖的一下回想起来了学习过的知识点,于是复习后总结一下,内容如下:
spring 的 bena 管理有一下几个作用域
在每个 Spring IoC 容器中一个 bean 定义只有一个对象实例。默认情况下会在容器启动时初始化 bean,但
我们可以指定 Bean 节点的 lazy-init=“true”来延迟初始化 bean,这时候,只有第一次获取 bean 会才初始化
bean。如:
<bean id="xxx" class="" lazy-init="true"/>
如果想对所有 bean 都应用延迟初始化,可以在根节点 beans 设置 default-lazy-init=“true“,如下:
<beans default-lazy-init="true“ ...>
每次从容器获取 bean 都是新的对象。
session
(其中后三个只有在 web 上下文环境中才能用)
由此不难看出报出如题的异常原因所在,这里顺便回顾下"延迟加载"的 概念我的项目中涉及到 tbrole 和
tbright 两张表,量表之间的关系为多对多,为了提高效率,建立了一个中间表 tbroleright 表,此表中存 放
前两张表的外键,在持久化类中将其映射为两个多对一关系,从而构成变相的多对多关系。于是在调用中
间表中的对象时就会涉及到另外的表的关系,因而有了 lazy-init(默认为 true),因此有时候我们可以将
lazy-init 设为 false,立即加载,这样虽然可以,但是浪费资源,所以一般我们会在 文件中添加如上
例子中的配置。