1. 程式人生 > >MyBatis筆記(二)————PersistenceException產生與解決 和 MyBatis的高階使用(主鍵回填)

MyBatis筆記(二)————PersistenceException產生與解決 和 MyBatis的高階使用(主鍵回填)

(MySQL+Eclipse)

 ①

十二月 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或者在XXXDAO.xml中有selectKey子元素的insert元素中加屬性useGeneratedKeys=“true”(來獲取有資料庫內部生成的主鍵)
3、對映檔案(XxxDAO.xml)中必須增加<selectKey>標籤,其標籤的keyColumn屬性:資料庫表的欄位名、 keyProperty屬性:Javabean的變數名(該值要與keyColumn值對應)、resultType屬性:select查詢的值的返回型別、order屬性(預設值為BEFORE):回填順序,在插入語句執行前或者在插入語句執行後獲取主鍵值(可選BEFORE或AFTER)

注:[一般SQLServer和MySQL的選AFTER,Oracle的選BEFORE  主鍵能自動遞增選擇AFTER,主鍵不能自動遞增則選擇BEFORE]

 (1)

【empId是自動遞增的主鍵欄位,且在mybatis配置檔案中加上“主鍵回填為true”的程式碼】

————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" >
        <!--empId是自動遞增的主鍵欄位-->
	<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");
                        //先將兩表的值都放在MappedStatement中,再一起commit(也可以先emp表commit再Emp_Account表commit,不過要比較下速度或效能)
			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);
		}
}

推薦看看(他人好文,註釋裡的MapperStatement就是在裡面看到的)——【原理分析之二:框架整體設計《深入理解mybatis原理》 MyBatis的架構設計以及例項分析——二、MyBatis的主要構件及其相互關係】 

Emp表和Emp_Account表的相同欄位為empId。以下為“新增介面”(含Emp_Account表對應控制元件;若值傳至後臺,兩表都要有對應變化,正如上面那兩張“empId都為1”資料庫表圖):

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

(2) 

自定義回填:

【主鍵empId欄位不能自動遞增,且在 XxxDAO配置檔案中加上“主鍵回填為true”的屬性】這樣就能夠通過編寫這個查詢語句,來自定義主鍵的生成規則(如:從1開始每次取最大值加1)。在插入時,需要將主鍵一起插入,因為這時DBMS並沒有自動生成主鍵,而是手動生成的。(將其order屬性設為BEFORE後,就可以在真正執行插入前執行一次查詢,並將結果填寫到要插入的主鍵上。)

    <!--開啟自定義生成主鍵,指明主鍵的那一列是名為id的列-->
    <insert id="addBook" parameterType="book" useGeneratedKeys="true" keyProperty="id">
        <!--查詢結果給empId屬性,查詢結果是int型別,查詢發生在真正執行插入之前-->
        <selectKey keyProperty="empId" resultType="int" order="BEFORE">
            SELECT IF(MAX(empId) is NULL,1,MAX(empId)+1) FROM emp
        </selectKey>
        INSERT INTO emp(empId,empName,age, sex) VALUES (#{empId},#{empName}, #{age},#{sex})
    </insert>

前提:empId是主鍵但不是"自動遞增",並且我的全部程式碼與(1)中程式碼呈現一模一樣。導致報錯:【在MyBatis筆記(一)————PersistenceException產生與解決(考考你CRUD基礎扎不紮實~)——③中也寫有這個異常】

十二月 18, 2018 11:06:11 上午 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: java.sql.SQLException: Field 'empId' doesn't have a default value
### The error may involve qiu.mapper.EmpDAO.addEmp2-Inline
### The error occurred while setting parameters
### SQL: insert into emp(empName,password,age,sex,depId,job,status,remark) values(?,?,?,?,?,?,?,?);
### Cause: java.sql.SQLException: Field 'empId' doesn't have a default value
	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.insert(DefaultSqlSession.java:185)
	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:57)
	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59)
	at com.sun.proxy.$Proxy4.addEmp2(Unknown Source)
	at qiu.servlet.EmpServlet.doPost(EmpServlet.java:96)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
	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:313)
	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: java.sql.SQLException: Field 'empId' doesn't have a default value
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:964)
	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.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.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.$Proxy9.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)
	... 29 more

所以解決(一步一步來 ):

將XxxDAO配置檔案中"id為addEmp"的insert元素裡的程式碼替換掉,

                                                                                                        改成

 還是會報錯:

( 前提:empId主鍵不能自動遞增。報錯原因:

一:insert語句中沒有empId欄位,導致報上面的異常 “Field 'empId' doesn't have a default value”                  

改為:

二:不能在插入執行後 回填主鍵值,因為會報下面的異常“Column 'empId' cannot be null”

改為:

按道理,做到這裡,是解決完了問題,

由於我將“add”與“update”合併在一起,而且將empVo(含有主鍵回填的empId)傳給方法,導致結果還是錯誤的或者出現了不想要的 “ 結果 ” :

---------------------***********給出對應程式碼************---------------------

————EmpVo
public class EmpVo implements Serializable{

	//可使用Integer包裝類的型別,不需要區分大小寫,但是必須與"資料表的欄位對應單詞",不可或多或少或寫錯
	private Integer empId;
	private String empName;
	private String password;
	private int age;
	private String sex;
	private int status;
	private int depId;
	private String job;
	private String remark;
	public Integer getEmpId() {
		return empId;
	}
	public void setEmpId(Integer empId) {
		this.empId = empId;
	}
	public String getEmpName() {
		return empName;
	}
	public void setEmpName(String empName) {
		this.empName = empName;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public int getStatus() {
		return status;
	}
	public void setStatus(int status) {
		this.status = status;
	}
	public int getDepId() {
		return depId;
	}
	public void setDepId(int depId) {
		this.depId = depId;
	}
	public String getRemark() {
		return remark;
	}
	public void setRemark(String remark) {
		this.remark = remark;
	}
	public String getJob() {
		return job;
	}
	public void setJob(String job) {
		this.job = job;
	}
	@Override
	public String toString() {
		String msg="empId="+empId+",empName="+empName+",password="+password+",age="+age+",sex="+sex+",status="+status+",depId="+depId+",job="+job+",remark="+remark;
		return msg;
	}
}

————EmpVo4
public class EmpVo4 implements Serializable{

	//可使用Integer包裝類的型別,不需要區分大小寫,但是必須與"資料表的欄位對應單詞",不可或多或少或寫錯
	private Integer empId;
	private String empName;
	private String password;
	private int age;
	private String sex;
	private int status;
	private String statusRemark;
	private int depId;
	private String depName;
	private String job;
	private String remark;
	
	private Emp_AccountVo eAcc;
	
	private Emp_TaskVo eTask;//一對一情況下用association標籤,在配置檔案中
	
	public String getStatusRemark() {
		return statusRemark;
	}
	public void setStatusRemark(String statusRemark) {
		this.statusRemark = statusRemark;
	}
	public String getDepName() {
		return depName;
	}
	public void setDepName(String depName) {
		this.depName = depName;
	}
	public Emp_AccountVo geteAcc() {
		return eAcc;
	}
	public void seteAcc(Emp_AccountVo eAcc) {
		this.eAcc = eAcc;
	}
	public Emp_TaskVo geteTask() {
		return eTask;
	}
	public void seteTask(Emp_TaskVo eTask) {
		this.eTask = eTask;
	}
	public Integer getEmpId() {
		return empId;
	}
	public void setEmpId(Integer empId) {
		this.empId = empId;
	}
	public String getEmpName() {
		return empName;
	}
	public void setEmpName(String empName) {
		this.empName = empName;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public int getStatus() {
		return status;
	}
	public void setStatus(int status) {
		this.status = status;
	}
	public int getDepId() {
		return depId;
	}
	public void setDepId(int depId) {
		this.depId = depId;
	}
	public String getJob() {
		return job;
	}
	public void setJob(String job) {
		this.job = job;
	}
	public String getRemark() {
		return remark;
	}
	public void setRemark(String remark) {
		this.remark = remark;
	}
	@Override
	public String toString() {
		String msg="empId="+empId+",empName="+empName+",password="+password+",age="+age+",sex="+sex+",status="+status+"(statusRemark="+statusRemark+"),depId="+depId+"(depName="+depName+"),job="+job+",remark="+remark+",taskName="+eTask.getTaskName()+",taskRemark="+eTask.getTaskRemark()+",bankName="+eAcc.getBankName()+",bankAccount="+eAcc.getBankAccount();
		return msg;
	}
}

————EmpDAO
        List<EmpVo> listemp();//介面,要定義方法,而不是變數,也不能static final,只能public和abstract	
	List<EmpVo4> listEmp_EAcc_ETask_EDep_EStatus();
	List<EmpVo4> listEmp_EAcc_ETask_EDep_EStatus_If(EmpVo empvo);

————EmpDAO配置檔案
    <resultMap type="qiu.vo.EmpVo4" id="allSelect">
		<id column="empId" property="empId"/>
		<result column="empName" property="empName"/>
		<result column="password" property="password"/>
		<result column="age" property="age"/>
		<result column="sex" property="sex"/>
		<result column="status" property="status"/>
		<result column="statusRemark" property="statusRemark"/>
		<result column="depId" property="depId"/>
		<result column="depName" property="depName"/>
		<result column="job" property="job"/>
		<result column="remark" property="remark"/>
		<association property="eTask" javaType="ETaskVo">
			<id column="empId" property="empId" />
			<result column="taskName" property="taskName"/>
			<result column="taskRemark" property="taskRemark"/>
		</association>
		<association property="eAcc" javaType="EAccVo">
			<id column="empId" property="empId" />
			<result column="bankName" property="bankName"/>
			<result column="bankAccount" property="bankAccount"/>
		</association>
	</resultMap>
	
	<!--select標籤都對應介面中的一個方法, 
		id屬性:指定介面中具體的方法名  ,  其值必須唯一   
		resultType:執行sql返回的結果型別,有時候也就是指定介面中對應方法的List的尖括號裡的Javabean
		
		xml的檔名稱必須與介面名稱相同,並且必須在同一個包中
	-->
	<select id="listemp" resultType="qiu.vo.EmpVo">
		<!--
			格式化sql語句的標籤;
			當"裡面的SQL語句裡含有特殊字元,如'小於號''大於號'",就能起到作用,處理"讀取時"異常;
			即,處理>,<等特殊符號時必須加上CDATA標記。
		-->
		<![CDATA[
			select * from Emp;
		]]>
	</select>
	<select id="listEmp_EAcc_ETask_EDep_EStatus" resultMap="allSelect">
		<!-- 
		
		如果association或collection 關聯物件對應的表中有欄位與主表字段同名,則必須通過欄位別名的方式區分開來,
		MyBatis最終是把別名對映到物件的屬性上。如departmentDetail中的depid列使用別名detail_id
		
		那是不是不給別名他就null???
		 -->
		<![CDATA[
			select e.*,d.depName,s.statusRemark,k.taskName,k.taskRemark,a.bankName,a.bankaccount from emp e
			inner join emp_dep d on d.depId=e.depId
			inner join emp_status s on s.statusId=e.status 
			left join emp_task k on  k.empId=e.empId 
			left join emp_account a on a.empId=e.empId
		]]>
	</select>
           <!--
                EmpVo型別傳進來,沒關係,反正只是為了做if判斷,改為empVo4型別,一樣的,因為一樣的變數,只不過empVo4多了Javabean物件
           -->
	<select id="listEmp_EAcc_ETask_EDep_EStatus_If" resultMap="allSelect">
		<![CDATA[
			select e.*,d.depName,s.statusRemark,k.taskName,k.taskRemark,a.bankName,a.bankaccount from emp e
			inner join emp_dep d on d.depId=e.depId
			inner join emp_status s on s.statusId=e.status 
			left join emp_task k on  k.empId=e.empId 
			left join emp_account a on a.empId=e.empId
		]]>
		<where>
			<if test="empName!=null and empName!='' ">
				and empName like concat('%',#{empName},'%')
			</if>
			<if test="status>-1 ">
				and status=#{status}
			</if>
			<if test="depId>0">
				and e.depId=#{depId}
			</if>
			<if test="sex!=null and sex!='' ">
				and sex=#{sex}
			</if>
			<if test="age>0 ">
				and age=#{age}
			</if>
		</where>
	</select>

————EmpServlet
    if(action.equals("add")){
			String id=request.getParameter("empId");
			String eage=request.getParameter("age");
			int  age=0;
			int empId=0;
			if(id==null && !id.equals("")){
				empId=Integer.parseInt(id);
			}
			//int型別的欄位對應的輸入框要是沒有填值,都會報錯"java.lang.NumberFormatException: null"
			if(!eage.equals("")){
				age=Integer.parseInt(eage);
			}
			String  empName=request.getParameter("empName");
			String  password=request.getParameter("password");
			int  depId=Integer.parseInt(request.getParameter("depId"));//下拉框一定賦值,零或者其他值
			String  sex=request.getParameter("sex");
//			int  status=Integer.parseInt(request.getParameter("status"));
			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);
			empaccVo.setBankName(bankName);
			empaccVo.setBankAccount(bankaccount);
			if(empId>0){
				empBase.undateEmpAll_SetIf(empVo);
				empaccVo.setEmpId(empVo.getEmpId());
				eaccBase.undateEacc(empaccVo);
			}else{
				empBase.addEmp2(empVo);//要先主鍵回填,才可以有empId,因為還沒有載入到資料庫表中
				empaccVo.setEmpId(empVo.getEmpId());
				eaccBase.addEacc(empaccVo);
			}
			sqlSession.commit();
//			List<EmpVo> eList=empBase.listemp();
			List<EmpVo4> eList=empBase.listEmp_EAcc_ETask_EDep_EStatus_If(empVo);
			request.setAttribute("empList", eList);
			request.getRequestDispatcher("EmpList.jsp").forward(request, response);
		}

要麼改為:

要麼初始化(因為status為0表示禁用或1表示啟用,所以-1才表示不選擇)為:

)

Opening JDBC Connection
Created connection 20026077.
Setting autocommit to false on JDBC Connection [[email protected]]
==>  Preparing: insert into emp(empId,empName,password,age,sex,depId,job,status,remark) values(?,?,?,?,?,?,?,?,?); 
==> Parameters: null, 111(String), 111(String), 111(Integer), 男(String), 6(Integer), 111(String), 1(Integer), 111(String)
十二月 18, 2018 8:57:45 下午 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.MySQLIntegrityConstraintViolationException: Column 'empId' cannot be null
### The error may involve qiu.mapper.EmpDAO.addEmp2-Inline
### The error occurred while setting parameters
### SQL: insert into emp(empId,empName,password,age,sex,depId,job,status,remark) values(?,?,?,?,?,?,?,?,?);
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'empId' cannot be null
	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.insert(DefaultSqlSession.java:185)
	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:57)
	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59)
	at com.sun.proxy.$Proxy12.addEmp2(Unknown Source)
	at qiu.servlet.EmpServlet.doPost(EmpServlet.java:96)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:646)
	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.MySQLIntegrityConstraintViolationException: Column 'empId' cannot be null
	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:935)
	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.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.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.$Proxy10.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)
	... 29 more

————————————————************************分割線******************************——————————————

分享(其中複習MySQL查詢知識):

{1}、【MyBatis學習筆記】8:增刪查改配置,結果集自動/自定義對映,主鍵回填/生成策略

(裡含 ‘ SELECT IF(MAX(id) is NULL,1,MAX(id)+2) FROM book ’ 語句,因為我不瞭解,所以找了:mysql 將null轉代為0(以及一些特殊用法)                                         )

======擴充套件======》Oracle也有實現這樣的函式:

“ Oracle 中 decode 函式用法 ”或者“ oracle decode函式使用方法(百度經驗)”或者“ decode函式(百度百科) ”【第二連結‘與第一連結相似(都講解了decode(...)、sign(...)函式)但在‘舉例方面’相對更完善些’】

Mysql實現oracle decode()函式

======擴充套件======》SQLServer也有實現這樣的方法:

資料庫--sqlserver--sqlserver 查詢 值如果為NULL則顯示0-解決方法

{2}、(mysql) select 時case、 if、 ifnull、nullif用法sql_不使用or查詢 0 和null_ISNULL(a.status,0)=0 和 case when else end(sql學習之CASE WHEN THEN ELSE END的用法case when then else end)、mysql 中 isnull 和 ifnull 判斷欄位是否為null關於SQL語句中SUM函式返回NULL的解決辦法(裡含COALESCE 函式,講解不是很詳細,而且我在Navicat Premium中查詢,

‘39行的結果列印為0,40行的結果列印為1’,所以找了:sql:函式:COALESCE()sql中的coalesceMYSQL-ORCALE decode函式在MYSQL中的實現MySQL sum()函式