mybatis入門之增刪改查
一、原生態JDBC程式中問題的總結
1.1 JDBC程式
需求:使用jdbc查詢mysql資料庫中使用者的記錄
Statement:向資料庫傳送回個sql語句
預編譯Statement: 好處:提高資料庫效能
預編譯Statement向資料庫傳送一個sql語句,資料庫執行後將執行結果存放在快取中,下次再執行相同的語句會直接從快取中讀取
1、 載入資料庫驅動
2、 建立並獲取資料庫連結
3、 建立jdbc statement物件
4、 設定sql語句
5、 設定sql語句中的引數(使用preparedStatement)
6、 通過statement執行sql並獲取結果
7、 對sql執行結果進行解析處理
8、 釋放資源(resultSet、preparedstatement、connection)
public class JDBCTest { public static void main(String[] args) { Connection connection = null; // 預編譯的Statement,使用預編譯的Statement提高資料庫效能 PreparedStatement preparedStatement = null; ResultSet resultSet = null; try { // 載入資料庫驅動 Class.forName("com.mysql.jdbc.Driver"); // 通過驅動管理類獲取資料庫連結 connection = DriverManager.getConnection( "jdbc:mysql://localhost:3306/test?characterEncoding=utf-8", "root", "root"); // 定義sql語句 ?表示佔位符 String sql = "select * from t_user where username = ?"; //獲取預處理statement preparedStatement = connection.prepareStatement(sql); // 設定引數,第一個引數為sql語句中引數的序號(從1開始),第二個引數為設定的引數值 preparedStatement.setString(1, "王五"); // 向資料庫發出sql執行查詢,查詢出結果集 resultSet = preparedStatement.executeQuery(); // 遍歷查詢結果集 while (resultSet.next()) { System.out.println(resultSet.getString("id") + ""+ resultSet.getString("username")); } } catch (Exception e) { e.printStackTrace(); } finally { //釋放資源 if (resultSet != null) { try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } } if (preparedStatement != null) { try { preparedStatement.close(); } catch (SQLException e) { e.printStackTrace(); } } if (connection != null) { try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
1.2問題總結:
上面程式碼的問題總結
1、資料庫連線,使用時就建立,不使用立即釋放,對資料庫進行頻繁連線開啟和關閉,造成資料庫資源浪費,影響 資料庫效能。
設想:使用資料庫連線池管理資料庫連線。
2、將sql語句硬編碼到java程式碼中,如果sql 語句修改,需要重新編譯java程式碼,不利於系統維護。
設想:將sql語句配置在xml配置檔案中,即使sql變化,不需要對java程式碼進行重新編譯。
3、向preparedStatement中設定引數,對佔位符號位置和設定引數值,硬編碼在java程式碼中,不利於系統維護。
設想:將sql語句及佔位符號和引數全部配置在xml中。
4、從resutSet中遍歷結果集資料時,存在硬編碼,將獲取表的欄位進行硬編碼,,不利於系統維護。
設想:將查詢的結果集,自動對映成java物件。
二、mybatis原理
2.1 mybatis是什麼?
mybatis是一個持久層的框架,是apache下的頂級專案。
mybatis託管到goolecode下,再後來託管到github下( ofollow,noindex">https://github.com/mybatis/mybatis-3/releases )。
mybatis讓程式將主要精力放在sql上,通過mybatis提供的對映方式,自由靈活生成(半自動化,大部分需要程式設計師編寫sql)滿足需要sql語句。
mybatis可以將向 preparedStatement中的輸入引數自動進行輸入對映,將查詢結果集靈活對映成java物件。(輸出對映)
2.2 mybatis框架

aaa.png
1、 mybatis配置
SqlMapConfig.xml,此檔案作為mybatis的全域性配置檔案,配置了mybatis的執行環境等資訊。
mapper.xml檔案即sql對映檔案,檔案中配置了操作資料庫的sql語句。此檔案需要在SqlMapConfig.xml中載入。
2、 通過mybatis環境等配置資訊構造SqlSessionFactory即會話工廠
3、 由會話工廠建立sqlSession即會話,操作資料庫需要通過sqlSession進行。
4、 mybatis底層自定義了Executor執行器介面操作資料庫,Executor介面有兩個實現,一個是基本執行器、一個是快取執行器。
5、 Mapped Statement也是mybatis一個底層封裝物件,它包裝了mybatis配置資訊及sql對映資訊等。mapper.xml檔案中一個sql對應一個Mapped Statement物件,sql的id即是Mapped statement的id。
6、 Mapped Statement對sql執行輸入引數進行定義,包括HashMap、基本型別、pojo,Executor通過Mapped Statement在執行sql前將輸入的java物件對映至sql中,輸入引數對映就是jdbc程式設計中對preparedStatement設定引數。
7、 Mapped Statement對sql執行輸出結果進行定義,包括HashMap、基本型別、pojo,Executor通過Mapped Statement在執行sql後將輸出結果對映至java物件中,輸出結果對映過程相當於jdbc程式設計中對結果的解析處理過程。
三、入門程式之mybatis增刪改查
3.1 需求
根據使用者id(主鍵)查詢使用者資訊
根據使用者名稱稱模糊查詢使用者資訊
新增使用者
刪除 使用者
更新使用者
3.2 PC環境
java環境:1.7.0_40
eclipse
mysql: 5.7
3.3 建立mysql資料庫
新建資料庫mybatis,新建表user

user詳細資訊
3.4所需Jar包
MyBatis下載地址: https://github.com/mybatis/mybatis-3/releases
mybatis-3.4.4.jar :核心包
mysql-connector-java-5.1.jar:mysql的驅動包
3.4 工程結構
在eclipse中新建java工程,建立下面的工程結構,並把jar把新增到lib中

ccc.png
3.5 配置log4j.properties
開發環境 下日誌級別設定為DEBUG, log4j.rootLogger=DEBUG, stdout; 生產環境設定為info或error
# Global logging configuration #\u5728\u5f00\u53d1\u73af\u5883\u4e0b\u65e5\u5fd7\u7ea7\u522b\u8981\u8bbe\u7f6e\u6210DEBUG\uff0c\u751f\u4ea7\u73af\u5883\u8bbe\u7f6e\u6210info\u6216error log4j.rootLogger=DEBUG, stdout # Console output... log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
3.6 配置SqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 載入屬性檔案 --> <properties resource="db.properties"> <!--properties中還可以配置一些屬性名和屬性值--> <!-- <property name="jdbc.driver" value=""/> --> </properties> <!-- 全域性配置引數,需要時再設定 --> <!-- <settings> </settings> --> <!-- 別名定義 --> <typeAliases> <!-- 針對單個別名定義 type:型別的路徑 alias:別名 --> <!-- <typeAlias type="cn.itcast.mybatis.po.User" alias="user"/> --> <!-- 批量別名定義 指定包名,mybatis自動掃描包中的po類,自動定義別名,別名就是類名(首字母大寫或小寫都可以) --> <package name="cn.itcast.mybatis.po"/> </typeAliases> <!-- 和spring整合後 environments配置將廢除--> <environments default="development"> <environment id="development"> <!-- 使用jdbc事務管理,事務控制由mybatis--> <transactionManager type="JDBC" /> <!-- 資料庫連線池,由mybatis管理--> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </dataSource> </environment> </environments> <!-- 載入 對映檔案 --> <mappers> <mapper resource="sqlmap/User.xml"/> </mappers> </configuration>
3.7 根據使用者id(主鍵)查詢使用者資訊
3.7.1 建立po類
在cn.eugene.po下建立user類
package cn.eugene.po; public class User { private int id; private String userName; private String userAge; private String userAddress; public User() { super(); // TODO Auto-generated constructor stub } /** * @return the id */ public int getId() { return id; } /** * @param id the id to set */ public void setId(int id) { this.id = id; } /** * @return the userName */ public String getUserName() { return userName; } /** * @param userName the userName to set */ public void setUserName(String userName) { this.userName = userName; } /** * @return the userAge */ public String getUserAge() { return userAge; } /** * @param userAge the userAge to set */ public void setUserAge(String userAge) { this.userAge = userAge; } /** * @return the userAddress */ public String getUserAddress() { return userAddress; } /** * @param userAddress the userAddress to set */ public void setUserAddress(String userAddress) { this.userAddress = userAddress; } @Override public String toString() { return "User [id=" + id + ", userName=" + userName + ", userAge=" + userAge + ", userAddress=" + userAddress + "]"; } }
3.7.2 對映檔案
在專案目錄的sqlmap下建立user的對映檔案userMapp.xml,並配置根據id查詢用的sql語句
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="test"> <!-- 根據id查詢使用者資訊 --> <select id="findUserById" parameterType="int" resultType="cn.eugene.po.User"> select * from user where id = #{id} </select> </mapper>
3.7.3 在SqlMapConfig.xml載入對映檔案
<mappers> <mapper resource="sqlmap/User.xml"/> </mappers>
3.7.4 編寫測試程式,根據id查詢使用者資訊
package cn.eugene.first; import java.io.IOException; import java.io.InputStream; import org.junit.Test; import cn.eugene.po.User; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class MybatisFirst { @Test public void findUserByIdTest() throws IOException{ //得到配置檔案流 String resource = "SqlMapConfig.xml"; InputStream inputstream = Resources.getResourceAsStream(resource); //建立會話工廠,傳入mybatis的配置檔案資訊 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream); //通過會話工廠得到SqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); User user = sqlSession.selectOne("test.findUserById", "1"); System.out.println(user); sqlSession.close(); } @Test public void deleteUser() throws IOException { String resource = "SqlMapConfig.xml"; InputStream inputstream = Resources.getResourceAsStream(resource); //建立會話工廠,傳入mybatis的配置檔案資訊 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream); //通過會話工廠得到SqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); sqlSession.delete("test.deleteUser", "2"); sqlSession.commit(); sqlSession.close(); } @Test public void updateUser() throws IOException { String resource = "SqlMapConfig.xml"; InputStream inputstream = Resources.getResourceAsStream(resource); //建立會話工廠,傳入mybatis的配置檔案資訊 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream); //通過會話工廠得到SqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); User user = new User(); user.setId(2); user.setUserName("出運費"); user.setUserAge("21"); user.setUserAddress("重慶"); sqlSession.update("test.updateUser", user); sqlSession.commit(); sqlSession.close(); } }
3.8 新增使用者
sql配置
<insert id="insertUser" parameterType="cn.eugene.po.User"> insert into user(userName,userAge,userAddress)VALUES(#{userName},#{userAge},#{userAddress}) </insert>
測試方法
@Test public void insertUser() throws IOException { String resource = "SqlMapConfig.xml"; InputStream inputstream = Resources.getResourceAsStream(resource); //建立會話工廠,傳入mybatis的配置檔案資訊 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream); //通過會話工廠得到SqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); User user = new User(); user.setUserName("出運費"); user.setUserAge("21"); user.setUserAddress("重慶2"); sqlSession.update("test.insertUser", user); sqlSession.commit(); sqlSession.close(); }
3.9 刪除使用者更新使用者
sql配置
<!-- 根據id刪除使用者 --> <delete id="deleteUser" parameterType="int"> delete from user where id = #{id} </delete> <update id="updateUser" parameterType="cn.eugene.po.User"> update user set userName=#{userName},userAge=#{userAge},userAddress=#{userAddress} where id= #{id} </update>
測試方法
@Test public void insertUser() throws IOException { String resource = "SqlMapConfig.xml"; InputStream inputstream = Resources.getResourceAsStream(resource); //建立會話工廠,傳入mybatis的配置檔案資訊 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream); //通過會話工廠得到SqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); User user = new User(); user.setUserName("出運費"); user.setUserAge("21"); user.setUserAddress("重慶2"); sqlSession.update("test.insertUser", user); sqlSession.commit(); sqlSession.close(); }
3.10新增使用者主鍵返回
<insert id="insertUser2" parameterType="com.ganlion.po.User"> <selectKey keyProperty="id" order="AFTER" resultType="int"> SELECT LAST_INSERT_ID() </selectKey> insert into user(userName,userAge,userAddress)VALUES(#{userName},#{userAge},#{userAddress}) </insert>
測試方法
@Test public void insertUser2(){ InputStream inputstream = Resources.getResourceAsStream(resource); //建立會話工廠,傳入mybatis的配置檔案資訊 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream); //通過會話工廠得到SqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); User user = new User(); user.setUserName("飛天"); user.setUserAge("24"); user.setUserAddress("上海浦江"); session.insert("test.insertUser2", user); session.commit(); System.out.println("返回的插入的主鍵id:"+user.getId()); session.close(); }
四、總結
sql配置檔案中
parameterType指定輸入引數型別
resultType指定輸出引數型別
#{}表示一個佔位符,#{}接收輸入引數。#{}可以有效防止sql注入。型別可以是簡單型別,pojo、hashmap。如果接收簡單型別,#{}中可以寫成value或其它名稱。
#{}接收pojo物件值,通過OGNL讀取物件中的屬性值,通過屬性.屬性.屬性...的方式獲取物件屬性值。
${}表示一個拼接符號,拼接sql串,會引起sql 注入存在安全隱患,所以不建議使用${}。${}接收輸入引數,型別可以是簡單型別,pojo、hashmap。如果接收簡單型別,${}中只能寫成value。
${}接收pojo物件值,通過OGNL讀取物件中的屬性值,通過屬性.屬性.屬性...的方式獲取物件屬性值。
五、編寫入門程式可能遇到的問題
問題一、Could not find resource SqlMapConfig.xml

ddd.png
原因:一開始是因為預設的情況下,只有src是build path的source folder目錄,自定義的資料夾在Use as Source Folder前只是一個普通的資料夾,預設的情況下不會被載入,需要手動將自定義的資料夾載入為source folder。也就是之前所說的步驟。
解決辦法:右鍵點選SqlMapConfig.xml所在的資料夾(我的是config)------>Build Path------>Use as Source Folder
參考 mybatis中遇到Could not find resource SqlMapConfig.xml
問題二、當查詢資料庫資料的時候,控制檯System.out.println(user)輸入了null
注意sql配置檔案查詢的欄位和資料庫對應