MyBatis筆記(二)————PersistenceException產生與解決 和 MyBatis的高級使用(運用於項目中)

 ①

十二月 11, 2018 5:02:00 下午 org.apache.catalina.core.StandardWrapperValve invoke
嚴重: Servlet.service() for servlet [empServlet] in context with path [/MyBatisQ] threw exception
org.apache.ibatis.exceptions.PersistenceException: 
### Error updating database.  Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
### The error may involve qiu.mapper.EmpDAO.delEmp-Inline
### The error occurred while setting parameters
### SQL: delete from emp where empid=?;
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
	at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:200)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.delete(DefaultSqlSession.java:213)
	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:67)
	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59)
	at com.sun.proxy.$Proxy49.delEmp(Unknown Source)
	at qiu.servlet.EmpServlet.doPost(EmpServlet.java:81)
	at qiu.servlet.EmpServlet.doGet(EmpServlet.java:35)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at qiu.base.EncodingFilter.doFilter(EncodingFilter.java:28)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:315)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
	at java.lang.reflect.Constructor.newInstance(Unknown Source)
	at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
	at com.mysql.jdbc.Util.getInstance(Util.java:408)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:951)
	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3973)
	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3909)
	at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2527)
	at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2680)
	at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2490)
	at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1858)
	at com.mysql.jdbc.PreparedStatement.execute(PreparedStatement.java:1197)
	at sun.reflect.GeneratedMethodAccessor59.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.apache.ibatis.logging.jdbc.PreparedStatementLogger.invoke(PreparedStatementLogger.java:59)
	at com.sun.proxy.$Proxy38.execute(Unknown Source)
	at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:46)
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:74)
	at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:50)
	at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117)
	at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:198)
	... 30 more

只是超時了,重啓Tomcat或編譯工具(MyEclipse、Eclipse。。。),http://blog.itpub.net/29654823/viewspace-2150471/https://blog.csdn.net/zc474235918/article/details/72731363/https://www.cnblogs.com/simpledev/p/5426705.html

MyBatis的主鍵回填:

1、在插入數據時,如果主鍵字段爲自動增長的字段,插入數據後想要知道主鍵值是多少,MyBatis提供了主鍵回填的功能
2、要使用主鍵回填的功能,MyBatis的配置文件mybatis.xml中<setting name=“useGeneratedKeys” value=“true”/>的value必須爲true
3、映射文件(XxxDAO.xml)中必須增加<selectKey>標籤

————mybatisQ.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- mybatis核心配置文件的dtd -->
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<!-- 引用jdbc配置文件 -->
	<properties resource="jdbc.properties"/>
	
	<settings>
		<setting name="cacheEnabled" value="true" /><!--二級緩存-->
		<setting name="useColumnLabel" value="true" />
		<setting name="useGeneratedKeys" value="true" /><!--主鍵回填-->
		<setting name="mapUnderscoreToCamelCase" value="true" />
		<setting name="logImpl" value="STDOUT_LOGGING" /><!-- 打印SQL語句 -->
	</settings>
	 <!-- 使用package爲整個包中所有的Javabean指定別名,使用typeAlias爲一個類指定別名,這兩個參數只能二選一 -->
	<typeAliases>
		<!-- 配置JAVABEAN的短名稱,使用時,首字母(其實別名都)不區分大小寫
			alias=別名
			type=類的全路徑(包含了包名)
		 -->
		<typeAlias  alias="EmpVo" type="qiu.vo.EmpVo"></typeAlias>
		<typeAlias  alias="EAccVo" type="qiu.vo.Emp_AccountVo"></typeAlias>
	</typeAliases>
	<!--環境配置,配置的是開發者模式(development),工作模式(work) -->
	<environments default="development">
		<environment id="development">
			<!-- 聲明jdbc事務處理,type=[JDBC、MANAGED] -->
			<transactionManager type="JDBC"></transactionManager>
			<!-- 數據源:數據庫連接池 ,type=[UNPOOLED、POOLED、]-->
			<dataSource type="POOLED">
				<!-- 	從這裏看出,jdbc.properties裏的參數名,可以自定義,
						最好帶個類似"jdbc."這樣的前綴,這樣不會和其他的properties的參數名弄混
				 -->
				<property name="driver" value="${jdbc.driverClassName}"/>
				<property name="url" value="${jdbc.driverUrl}"/>
				<property name="username" value="${jdbc.user}"/>
				<property name="password" value="${jdbc.password}"/>
			</dataSource>
		</environment>
	</environments>
	<!-- mappers可以一個一指定,也可以通過包一次性指定(二選一) -->
   	<!-- 引用Mapper接口的sql映射文件 -->
    <mappers>
    	<package name="qiu/mapper"></package>
    </mappers>
</configuration>

————DBConnQ.class
public class DBConnQ {
	static SqlSession session=null;
	public static SqlSession getSession(){
		try {
			InputStream configuration=Resources.getResourceAsStream("mybatisQ.xml");
			SqlSessionFactory sessionFactory= new SqlSessionFactoryBuilder().build(configuration);
			session=sessionFactory.openSession();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return session;
	}
}

————EmpDAO.xml
<insert id="addEmp" parameterType="qiu.vo.EmpVo" >
	<selectKey keyColumn="empId" keyProperty="empId" resultType="int" order="AFTER">
		SELECT LAST_INSERT_ID()
	</selectKey>
	<![CDATA[
                insert into emp(empName,password,age,sex,depId,job,status,remark) values(#{empName},#{password},#{age},#{sex},#{depId},#{job},#{status},#{remark});
	]]>
</insert>
————EmpDAO.class
void addEmp(EmpVo empvo);

————Emp_AccountDAO.xml
<insert id="addEacc" parameterType="qiu.vo.Emp_AccountVo" >
	<![CDATA[
		insert into Emp_Account(empId,bankName,bankaccount) values(#{empId},#{bankName},#{bankAccount});
	]]>
</insert>
————Emp_AccountDAO.class
void addEacc(Emp_AccountVo eaccvo);

—————將add頁面的form傳來的值接收(我使用Servlet)
@ WebServlet(name = "empServlet", urlPatterns = { "/empServlet" })
public class EmpServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doPost(request,response);
	}
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		SqlSession sqlSession=DBConnQ.getSession();
		EmpDAO empBase=sqlSession.getMapper(EmpDAO.class);
		EmpVo empVo=new EmpVo();
		Emp_AccountVo empaccVo=new Emp_AccountVo();
		Emp_AccountDAO eaccBase=sqlSession.getMapper(Emp_AccountDAO.class);
                //localhost:8080/MyBatisQ/empServlet?action=add
		String action=request.getParameter("action");
        if(action.equals("add")){
			String  empName=request.getParameter("empName");
			String  password=request.getParameter("password");
			int  age=Integer.parseInt(request.getParameter("age"));
			String  sex=request.getParameter("sex");
			int  depId=Integer.parseInt(request.getParameter("depId"));
			String  remark=request.getParameter("remark");
			String  bankName=request.getParameter("bankName");
			String  bankaccount=request.getParameter("bankaccount");
			String  job=request.getParameter("job");
			empVo.setEmpName(empName);
			empVo.setPassword(password);
			empVo.setAge(age);
			empVo.setSex(sex);
			empVo.setDepId(depId);
			empVo.setStatus(1);//默認爲在職
			empVo.setRemark(remark);
			empVo.setJob(job);
			empBase.addEmp(empVo);//要先主鍵回填,纔可以有empId,因爲還沒有加載到數據庫表中
			empaccVo.setEmpId(empVo.getEmpId());
			empaccVo.setBankName(bankName);
			empaccVo.setBankAccount(bankaccount);
			eaccBase.addEacc(empaccVo);
			sqlSession.commit();
                        //以下轉向EmpList列表頁面(無需提供對應代碼)
			List<EmpVo> eList=empBase.listemp();
			request.setAttribute("empList", eList);
			request.getRequestDispatcher("EmpList.jsp").forward(request, response);
		}
}

Emp表和Emp_Account表的相同字段爲empId。以下爲“新增界面”(含Emp_Account表對應控件;若值傳至後臺,兩表都要有對應變化,正如上面那兩張“empId都爲1”數據庫表圖):

所以要實現“添加了Emp表記錄的同時也添加Emp_Account表記錄”,就要使用主鍵回填,將未commit於數據庫表的主鍵值賦於empVo的empId屬性,那麼這條語句的getEmpId()有對應的主鍵值;若無主鍵回填,還使用這條語句,就會報NullPointerException——500異常。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章