最近在mybatis多線程插入數據時出現兩則問題,記錄如下:
問題1:我的邏輯如下
1 select表中category_name字段,如果有的話則取出其ID
2 如果木有的話則插入一條數據,同時用last_insert_id()函數將主鍵主增長ID找出
mybatis配置如下
<insert id="insertCommonCategory" parameterType="CommonCategory"> insert ignore into common_category (category_name,category_group) values(#{categoryName},#{categoryGroup}) <!-- 多線程環境中會導致insert失敗,導致該段邏輯有誤 <selectKey keyProperty="id" resultType="java.lang.Integer"> select last_insert_id() as id </selectKey> --> </insert> <select id="selectIdbyCategoryNameAndGroup" parameterType="CommonCategory" resultType="java.lang.Integer"> select id from common_category where category_name=#{categoryName} and category_group=#{categoryGroup} </select>
由於在多線程環境中,可能會導致邏輯同時進入2邏輯,此時會導致insert失敗,last_insert_id()函數返回一個錯誤的id
問題2:根據以上現象,我的更改為
1 在insert加上ignore修飾,可讓insert失敗時不報錯,但last_insert_id()函數依然有錯,所以不用它
2 將邏輯改成 (1) 查找category_name字段,有的時候取出其ID,(2)木有的話新插入一條,insert語句加上ignore修飾,(3)重新進行(1)步驟
但此時依然報錯,說是(3)步驟依然找不到ID,翻閱相關資料找到的原因為:Mysql的事務隔離級別為可重讀, 即在同一個事務中始終看到相同的數據,此時錯誤發生的原因為,在進行(2)步驟時,insert失敗,(3)步驟依然就查不到數據了,解決辦法有二
1 更改mysql事務隔離級別Read Commited或更低級別
2 利用mybatis的cache,在mapper的配置文件中加上<cache/>標簽,然后insert標簽上flushCache屬性設置為true,使其在多線程環境中能隨時的刷新cache
看來多線程編程有很多難以預料的問題