MyBatis學習(一)
一、MyBatis簡介
MyBatis是一個對JDBC進行封裝的持久層框架,只需關註SQL本身,而不必去處理(註冊驅動、創建connection、創建statement、手動設置參數、結果集檢查)的代碼。
XML或註解將要執行的statement配置起來,通過Java對象和statement的sql進行映射,生成最終的sql語句,由MyBatis框架執行sql並將結果映射成Java對象返回。
MyBatis和Hibernate的區別:
1、不完全的ORM框架,需要sql語句
2、直接寫sql語句,靈活度高,性能好
3、與數據庫相關(MySQL、Oracle用不同映射文件)
JDBC存在的問題:
1、創建連接connection、釋放資源影響性能(數據庫連接池可解決)
2、(sql、參數、結果集)硬編碼,代碼不易維護
二、MyBatis架構
1、SqlMapConfig.xml是核心配置文件,配置運行環境等信息;Mapper.xml是映射配置文件,配置了操作數據庫的sql語句,需要在SqlMapConfig.xml中配置。
2、通過MyBatis環境等配置信息構造會話工廠SqlSessionFactory。
3、由會話工廠SqlSessionFactory創建會話sqlSession,由sqlSession操作數據庫。
4、底層通過Executor執行器接口操作數據庫,接口有兩個實現:基本執行器、緩存執行器
5、Mapped Statement也是一個底層封裝對象,包裝了MyBatis配置信息和sql映射信息等。映射配置文件Mapper.xml中一個sql對應一個Mapped Statement對象,sql的id即是MappedStatement的id。
6、Mapped Statement對sql執行輸入參數進行定義,包括HashMap、基本類型、POJO、Executor通過Mapped Statement在執行sql前將輸入的Java對象映射至sql中,輸入參數映射就是JDBC中對prepareStatement設置參數
7、Mapped Statement對sql執行輸出結果進行定義,包括HashMap、基本類型、POJO、Executor通過Mapped Statement在執行sql後將輸出結果映射到Java對象中,輸出結果映射過程相當於JDBC中對結果的解析處理過程。
三、MyBatis入門
1、導包
核心包:MyBatis-3.2.7.jar
依賴包:lib下所有包
數據庫驅動包:mysql-connector-java-5.1.17-bin.jar
日誌配置文件:log4j.properties
2、在src下創建核心配置文件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> <!-- 和spring整合後 environments配置將廢除--> <environments default="development"> <environmentid="development"> <!-- 使用jdbc事務管理--> <transactionManagertype="JDBC"/> <!-- 數據庫連接池--> <dataSourcetype="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8"/> <property name="username" value="root"/> <property name="password "value="root"/> </dataSource> </environment> </environments> </configuration>
3、創建POJO(JavaBean) User,屬性表與表中字段對應
Public class User { privateintid; private String username;// 用戶姓名 private String sex;// 性別 private Date birthday;// 生日 private String address;// 地址 setter&getter }
4、在src下創建映射配置文件User.xml
<?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"> </mapper>
namespace用於隔離sql語句
5、加載映射文件User.xml到SqlMapConfig.xml
<mappers> <mapperresource="sqlmap/User.xml"/> </mappers>
四、增刪改查用戶
1、根據ID查詢用戶信息
1.1 User.xml中
<!-- 根據id獲取用戶信息 --> <select id="findUserById" parameterType="Integer" resultType="cn.guojie.mybatis.domain.User"> // MyBatis已為Java.lang.Integer用別名Integer select * from user where id = #{id} </select>
parameterType:入參類型,通過ONGL從輸入對象中獲取參數值拼接到sql中
resultType:返回結果集類型,將sql查詢結果的一行記錄數據映射為resultType指定的類型對象
#{id}:設置占位符,並將入參id傳給sql
1.2 測試
public class UserTest { //會話工廠,單例,可重復使用 private SqlSessionFactory sqlSessionFactory; @Before // 在測試方法前執行 public void createSqlSessionFactory() throws IOException { // 讀取核心配置文件 String resource = "SqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); // 創建SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder() .build(inputStream); } // 根據 id查詢用戶信息 @Test public void testFindUserById() { // 數據庫會話實例 SqlSession sqlSession = null; try { // 創建數據庫會話實例sqlSession sqlSession = sqlSessionFactory.openSession(); // 查詢單個記錄,根據用戶id查詢用戶信息,查詢多條記錄用selectList,命名空間+.+sql中的id User user = sqlSession.selectOne("test.findUserById", 10); System.out.println(user); } catch (Exception e) { e.printStackTrace(); } finally { if (sqlSession != null) { sqlSession.close(); } } } }
2、根據用戶名查詢用戶信息
2.1 User.xml中
<!-- 自定義條件查詢用戶列表 --> <select id="findUserByUsername" parameterType="java.lang.String" resultType="cn.guojie.mybatis.domain.User"> select * from user where username like ‘%${value}%‘ // 也可以是"%"#{id}"%" </selec
${}:拼接字符串,基本類型必須用value
2.2 測試
// 根據用戶名稱模糊查詢用戶信息 @Test public void testFindUserByUsername() { // 數據庫會話實例 SqlSession sqlSession = null; try { // 創建數據庫會話實例sqlSession sqlSession = sqlSessionFactory.openSession(); // 模糊查詢,查詢用戶名為張的用戶 List<User> list = sqlSession.selectList("test.findUserByUsername", "張"); System.out.println(list.size()); } catch (Exception e) { e.printStackTrace(); } finally { if (sqlSession != null) { sqlSession.close(); } } }
#{}和${}的區別:
#{}:占位符,防止SQL註入,通常在=後
${}:拼串,只能是value,將參數拼接到sql中。在頁面或者action中校驗,不可輸入SQL關鍵字和空格來防止SQL註入。通常在like後
3、添加用戶
3.1 User.xml中
<!-- 添加用戶 --> <inser tid="insertUser" parameterType="cn.guojie.mybatis.domain.User"> insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address}) </insert>
3.2 測試
// 添加用戶信息 @Test public void testInsert() { // 數據庫會話實例 SqlSession sqlSession = null; try { // 創建數據庫會話實例sqlSession sqlSession = sqlSessionFactory.openSession(); // 添加用戶信息 User user = new User(); user.setUsername("張小明"); user.setAddress("河南鄭州"); user.setSex("1"); user.setPrice(1999.9f); sqlSession.insert("test.insertUser", user); //提交事務,需要手動提交事務 sqlSession.commit(); } catch (Exception e) { e.printStackTrace(); } finally { if (sqlSession != null) { sqlSession.close(); } } }
4、MySQL自增主鍵返回
用來查詢上一個插入的ID
<insert id="insertUser" parameterType="cn.guojie.mybatis.domain.User"> <!-- selectKey將主鍵返回,需要再返回 --> <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer"> select LAST_INSERT_ID() </selectKey> insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address}); </insert>
LAST_INSERT_ID():數據庫海曙,返回自增的主鍵
keyProperty: 將返回的主鍵放入入參id中保存
order:相對於insert語句的執行順序
resultType:id的類型,也就是keyproperties中屬性的類型
5、MySQL中用UUID實現主鍵
<insert id="insertUser" parameterType="cn.guojie.mybatis.domain.User"> <selectKey resultType="java.lang.String" order="BEFORE" keyProperty="id"> select uuid() </selectKey> insert into user(id,username,birthday,sex,address) values(#{id},#{username},#{birthday},#{sex},#{address}) </insert>
6、刪除用戶
6.1 User.xml中
<!-- 刪除用戶 --> <delete id="deleteUserById" parameterType="int"> delete from user where id=#{id} </delete>
6.2 測試
// 根據id刪除用戶 @Test public void testDelete() { // 數據庫會話實例 SqlSession sqlSession = null; try { // 創建數據庫會話實例sqlSession sqlSession = sqlSessionFactory.openSession(); // 刪除用戶 sqlSession.delete("test.deleteUserById",18); // 提交事務 sqlSession.commit(); } catch (Exception e) { e.printStackTrace(); } finally { if (sqlSession != null) { sqlSession.close(); } } }
7、修改用戶
7.1 User.xml
<!-- 更新用戶 --> <update id="updateUser" parameterType="cn.guojie.mybatis.domain.User"> update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id} </update>
7.2 測試
@Test public void testUpdate() { // 數據庫會話實例 SqlSession sqlSession = null; try { // 創建數據庫會話實例sqlSession sqlSession = sqlSessionFactory.openSession(); // 添加用戶信息 User user = new User(); user.setId(16); user.setUsername("張小明"); user.setAddress("河南鄭州"); user.setSex("1"); user.setPrice(1999.9f); sqlSession.update("test.updateUser", user); // 需要手動提交事務 sqlSession.commit(); } catch (Exception e) { e.printStackTrace(); } finally { if (sqlSession != null) { sqlSession.close(); } } }
SqlSession不是線程安全的,在方法體中創建與銷毀
五、DAO開發
1、原始DAO開發(用得少)
需要DAO接口及其實現類
不足:
(1) 方法中代碼重復(sqlSessionFactory創建SqlSession,調用SqlSession的數據可操作方法)
(2)硬編碼(SqlSession操作方法需要指定statement的id)
2、Mapper動態代理(常用)
只需Mapper接口(相當於DAO接口),MyBatis根據接口定義創建接口的動態代理對象
2.1 開發規範
(1)接口方法名和mapper.xml中id名相同
(2)入參類型和mapper.xml中入參parammeterType相同
(3)返回值類型和mapper.xml的返回類型resultType相同
(4)接口類全路徑(包名+類名)和mapper.xml中命名空間相同
2.2 映射文件UserMapper.xml 放在mapper包下
<?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="cn.guojie.mybatis.mapper.UserMapper"> ----> 4 <!-- 根據id獲取用戶信息 --> <select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User"> ----> 1 2 3 select * from user where id = #{id} </select> <!-- 自定義條件查詢用戶列表 --> <select id="findUserByUsername" parameterType="java.lang.String" resultType="cn.guojie.mybatis.domain.User"> select * from user where username like ‘%${value}%‘ </select> <!-- 添加用戶 --> <inser tid="insertUser"parameter Type="cn.guojie.mybatis.domain.User"> <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer"> select LAST_INSERT_ID() </selectKey> insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address}) </insert> </mapper>
2.3 UserMapper接口 和映射文件放在同一目錄
Public interface UserMapper { //根據用戶id查詢用戶信息 public User findUserById(int id) throws Exception; //查詢用戶列表 public List<User> findUserByUsername(String username) throws Exception; //添加用戶信息 publicvoid insertUser(User user)throws Exception; }
2.4 加載UserMapper.xml
<!-- 加載映射文件 --> <mappers> <mapper resource="mapper/UserMapper.xml"/> </mappers>
2.5 測試
Public class UserMapperTest { private SqlSessionFactory sqlSessionFactory; @Before protectedvoid setUp() throws Exception { // 加載mybatis配置文件 String resource = "sqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); // 創建sessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } @Test Public void testFindUserById() throws Exception { // 獲取session SqlSession session = sqlSessionFactory.openSession(); // 獲取mapper接口的代理對象 UserMapper userMapper = session.getMapper(UserMapper.class); // 調用代理對象方法 User user = userMapper.findUserById(1); System.out.println(user); // 關閉session session.close(); } @Test public void testFindUserByUsername() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); List<User> list = userMapper.findUserByUsername("張"); System.out.println(list.size()); } @Test Public void testInsertUser() throws Exception { //獲取session SqlSession session = sqlSessionFactory.openSession(); //獲取mapper接口的代理對象 UserMapper userMapper = session.getMapper(UserMapper.class); //要添加的數據 User user = new User(); user.setUsername("張三"); user.setBirthday(new Date()); user.setSex("1"); user.setAddress("北京市"); //通過mapper接口添加用戶 userMapper.insertUser(user); //提交 session.commit(); //關閉session session.close(); } }
六、核心配置文件SqlMapConfig.xml
1、<properties>
在src下定義db.properties,其中不能有空格
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8 jdbc.username=root jdbc.password=root
SqlMapConfig.xml中引用
<properties resource="db.properties"/> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <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> </properties>
2、<typeAliases> 別名
<typeAliases> <!-- 單個別名定義 --> <typeAliasalias="user"type="cn.itcast.mybatis.po.User"/> <!-- 批量別名定義,掃描整個包下的類,別名為類名(首字母大寫或小寫都可以) --> // 常用 <packagename="cn.guojie.mybatis.domain"/> <packagename="其它包"/> </typeAliases>
3、<mapper>映射
resource=UserMapper.xml的類路徑
class=UserMapper接口的類路徑,要求mapper接口和mapper.xml同名且在同一目錄中
<package class="接口 " /> 註冊包下所有接口(常用),要求mapper接口和mapper.xml同名且在同一目錄中
MyBatis學習(一)