日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

MyBatis 实践 -Mapper与DAO

發(fā)布時間:2025/3/17 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MyBatis 实践 -Mapper与DAO 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

MyBatis 實踐

標簽: Java與存儲


MyBatis簡介

MyBatis前身是iBatis,是一個基于Java的數(shù)據(jù)持久層/對象關系映射(ORM)框架.

MyBatis是對JDBC的封裝,使開發(fā)人員只需關注SQL本身,而不需花費過多的精力去處理如注冊驅動設置參數(shù)、創(chuàng)建Connection/Statement、解析結果集等JDBC過程性代碼.MyBatis基于XML/注解的方式配置Statement,執(zhí)行SQL,并將執(zhí)行結果映射成Java對象, 大大降低了數(shù)據(jù)庫開發(fā)的難度.

MyBatis is a first class persistence framework with support for custom SQL, stored procedures and advanced mappings. MyBatis eliminates almost all of the JDBC code and manual setting of parameters and retrieval of results. MyBatis can use simple XML or Annotations for configuration and map primitives, Map interfaces and Java POJOs (Plain Old Java Objects) to database records.
– MyBatis項目地址/在線文檔.


初識MyBatis

使用MyBatis需要在pom.xml中添加如下依賴:

<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.3.0</version> </dependency> <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.36</version> </dependency>

Select

  • 配置mybatis/mybatis-configuration.xml
    作為MyBatis的全局配置文件,其配置了MyBatis的運行環(huán)境信息(如數(shù)據(jù)源/mapper文件等).
<?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><environments default="development"><environment id="development"><!-- 配置JDBC事務管理--><transactionManager type="JDBC"/><!-- 配置數(shù)據(jù)源--><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://host:port/db?characterEncoding=utf-8"/><property name="username" value="username"/><property name="password" value="password"/></dataSource></environment></environments><!-- 加載mapper映射文件 --><mappers><mapper resource="mybatis/mapper/UserDAO.xml"/></mappers> </configuration>
  • 書寫UserDAO(mapper映射)
    最為MyBatis最核心的部分,配置了操作數(shù)據(jù)庫的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="namespace"><select id="selectUserById" parameterType="java.lang.Integer" resultType="com.fq.domain.User">SELECT * FROM user WHERE id = #{id};</select><select id="selectUserByName" parameterType="java.lang.String" resultType="com.fq.domain.User">SELECT * FROM user WHERE name LIKE '%${value}%';</select></mapper> 屬性描述
namespace命名空間,用于隔離SQL語句
parameterType定義SQL輸入映射類型,MyBatis通過OGNL從輸入對象中獲取參數(shù)傳入SQL語句.
resultType定義SQL輸出映射類型,MyBatis將SQL查詢結果的一行記錄映射為resultType指定的類型.

mapper映射文件名有UserDAO.xml/UserMapper.xml/User.xml等幾種形式, 其一般存放在與mybatis-configuration.xml同級的mapper目錄下,由于其主要作用為定義SQL語句與映射關系, 因此一般統(tǒng)稱為mapper映射文件.

  • 定義PO類
    PO類主要作用為SQL(輸入/輸出)映射,通常與數(shù)據(jù)庫表對應:
/*** @author jifang* @since 15/12/31 下午2:27.*/ public class User {private Integer id;private String name;private String password;public User() {}public User(Integer id, String name, String password) {this.id = id;this.name = name;this.password = password;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", password='" + password + '\'' +'}';} }
  • UserDAO(Java對象)
    獲得SqlSession,執(zhí)行SQL語句, 得到映射結果:
/*** @author jifang* @since 16/2/24 下午6:15.*/ public class UserDAO {private SqlSessionFactory factory;@Beforepublic void setUp() throws IOException {String resource = "mybatis/mybatis-configuration.xml";factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream(resource));}@Testpublic void selectUserById() {try (SqlSession session = factory.openSession()) {User user = session.selectOne("namespace.selectUserById", 1);System.out.println(user);}}@Testpublic void selectUserByName() {try (SqlSession session = factory.openSession()) {List<User> users = session.selectList("namespace.selectUserByName", "student");for (User user : users) {System.out.println(user);}}} }

Insert

  • mapper
<insert id="insertUser" parameterType="com.fq.domain.User">INSERT INTO user(name, password) VALUES(#{name}, #{password}); </insert>
  • UserDAO
@Test public void insertUser() {try (SqlSession session = factory.openSession()) {User user = new User();user.setName("new_name1");user.setPassword("new_password");session.insert("namespace.insertUser", user);session.commit();} }

自增主鍵返回

修改mapper文件,添加<selectKey/>,可以將MySQL的自增主鍵(即剛剛插入數(shù)據(jù)時生成的ID)返回:

<insert id="insertUser" parameterType="com.fq.domain.User"><selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">SELECT LAST_INSERT_ID();</selectKey>INSERT INTO user(name, password) VALUES(#{name}, #{password}); </insert> 屬性描述
keyProperty指定存儲到DO中的哪個屬性;
orderselectKey執(zhí)行順序(相對于insert語句),AFTER/BEFORE;
resultType主鍵返回類型(DO中對應屬性的類型);
LAST_INSERT_ID()MySQL函數(shù),返回auto_increment自增列新記錄值.
  • UserDAO
@Test public void insertUser() {try (SqlSession session = factory.openSession()) {System.out.println(session);User user = new User(null, "new_name", "new_password");session.insert("namespace.insertUser", user);// 需要在commit之后才能獲得自增主鍵session.commit();System.out.println(user.getId());} }

該功能還可以通過<insert/>的useGeneratedKeys/keyProperty兩個屬性合作完成, 詳見MyBatis文檔.


Update

  • mapper
<update id="updateUserById" parameterType="com.fq.domain.User">UPDATE user SET name = #{name}, password = #{password} WHERE id = #{id}; </update>
  • UserDAO
@Test public void updateUserById() {try (SqlSession session = factory.openSession(true)) {session.update("namespace.updateUserById",new User(1, "feiqing", "ICy5YqxZB1uWSwcVLSNLcA=="));} }

Delete

  • mapper
<delete id="deleteUserById" parameterType="java.lang.Integer">DELETE FROM user WHERE id = #{id}; </delete>
  • UserDAO
@Test public void deleteUserById() {try (SqlSession session = factory.openSession(true)) {session.delete("namespace.deleteUserById", 51615);} }

小結

  • #{}/${}

    • #{}: 表示一個占位符號,實現(xiàn)向PreparedStatement占位符中設置值(#{}表示一個占位符?),自動進行Java類型到JDBC類型的轉換(因此#{}可以有效防止SQL注入).#{}可以接收簡單類型或PO屬性值,如果parameterType傳輸?shù)氖菃蝹€簡單類型值,#{}花括號中可以是value或其它名稱.
    • ${}: 表示拼接SQL串,通過${}可將parameterType內容拼接在SQL中而不進行JDBC類型轉換,${}可以接收簡單類型或PO屬性值,如果parameterType傳輸?shù)氖菃蝹€簡單類型值,${}花括號中只能是value.
      雖然${}不能防止SQL注入,但有時${}會非常方便(如order by排序,需要將列名通過參數(shù)傳入SQL,則用ORDER BY ${column},使用#{}則無法實現(xiàn)此功能(詳見JDBC基礎關于PreparedStatement的討論).
  • SqlSession
    提供操作數(shù)據(jù)庫的方法(如:selectOne/selectList).但SqlSession是線程不安全的,因此最好將其定義成局部變量使用.

  • MyBatis優(yōu)點(與JDBC相比)
    • SQL寫在Java代碼中導致不易維護, 而MyBatis將SQL寫在mapper中,XML與Java代碼分離.
    • 向SQL語句傳參繁瑣(如:SQL的where條件不一,SQL數(shù)據(jù)類型與Java不同),MyBatis通過parameterType自動將Java對象映射至SQL語句.
    • 結果集解析麻煩(SQL變化導致解析代碼變化,SQL數(shù)據(jù)類型與Java不同),MyBatis通過resultType自動將SQL執(zhí)行結果映射成Java對象.

附: 最好在pom.xml中添加一個日志系統(tǒng)實現(xiàn)(logback/log4j), 這樣會在調試程序時打印日志信息,便于查錯, 以logback為例:

  • pom.xml
<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.1.2</version> </dependency>
  • logback.xml
<configuration><property name="logRoot" value="/data/logs"/><property name="pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{0} - %msg%n"/><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>${pattern}</pattern></encoder></appender><appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>${logRoot}/common-server.%d{yyyy-MM-dd}.log</fileNamePattern><maxHistory>7</maxHistory></rollingPolicy><encoder><pattern>${pattern}</pattern></encoder></appender><root level="DEBUG"><appender-ref ref="STDOUT"/><appender-ref ref="FILE"/></root></configuration>

其他關于MyBatis日志的詳細信息可參考MyBatis文檔日志部分.


DAO開發(fā)

使用MyBatis開發(fā)DAO有兩個方法,原始DAO開發(fā)Mapper映射DAO開發(fā).


原始DAO開發(fā)

原始DAO開發(fā)需要開發(fā)人員編寫DAO接口DAO實現(xiàn),如根據(jù)ID查詢用戶信息:

  • mapper(同前)
<select id="selectUserById" parameterType="java.lang.Integer" resultType="com.fq.domain.User">SELECT * FROM user WHERE id = #{id}; </select>
  • UserDAO接口
/*** @author jifang* @since 16/2/22 上午10:20.*/ public interface UserDAO {User selectUserById(Integer id) throws Exception; }
  • UserDAO實現(xiàn)
public class UserDAOImpl implements UserDAO {private SqlSessionFactory factory;public UserDAOImpl(SqlSessionFactory factory) {this.factory = factory;}@Overridepublic User selectUserById(Integer id) throws Exception {SqlSession session = factory.openSession();User user = session.selectOne("namespace.selectUserById", id);session.close();return user;} }
  • Client
public class MyBatisClient {@Testpublic void originalClient() throws Exception {UserDAO dao = new UserDAOImpl(new SqlSessionFactoryBuilder().build(ClassLoader.getSystemResourceAsStream("mybatis/mybatis-configuration.xml")));User user = dao.selectUserById(1);System.out.println(user);} }
  • 原始DAO開發(fā)中存在的問題:
    1) DAO實現(xiàn)方法體中存在很多過程性代碼.
    2) 調用SqlSession的方法(select/insert/update)需要指定Statement的id,存在硬編碼,不利于代碼維護.

Mapper映射開發(fā)

mapper映射開發(fā)方法只需編寫DAO接口,MyBatis根據(jù)接口定義與mapper文件中的SQL語句動態(tài)創(chuàng)建接口實現(xiàn).

  • 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="com.fq.mybatis.UserDAO"><select id="selectUserById" parameterType="java.lang.Integer" resultType="com.fq.domain.User">SELECT * FROM user WHERE id = #{id};</select> </mapper>

注意: 此時namespace必須與UserDAO接口的全限定名相同.

  • UserDAO接口與前面相同, 但不再使用UserDAOImpl
  • Client
/*** @author jifang* @since 16/2/22 下午2:57.*/ public class MyBatisClient {private SqlSession session;private SqlSessionFactory factory;@Beforepublic void setUp() {factory = new SqlSessionFactoryBuilder().build(ClassLoader.getSystemResourceAsStream("mybatis/mybatis-configuration.xml"));session = factory.openSession();}@Testpublic void mapperClient() throws Exception {UserDAO dao = session.getMapper(UserDAO.class);User user = dao.selectUserById(1);System.out.println(user);}@Afterpublic void tearDown() {session.close();} }
  • mapper映射開發(fā)方法需要遵循以下規(guī)范:
  • mapper文件中的namespace與DAO接口的全限定名相同;
  • mapper文件中的Statement的id與DAO接口方法名相同;
  • mapper文件中的Statement的parameterType/resultType與DAO方法的入?yún)?回參類型相同.

Mapper映射

mapper映射文件(如UserDAO.xml)主要作用是定義SQL語句(每個SQL是一個Statement),是MyBatis的核心.

MyBatis官方推薦使用mapper映射的方法來開發(fā)DAO,因此我們以后就不再過多介紹原始DAO的開發(fā).


輸入映射

多個形參

傳遞簡單類型前面示例已經(jīng)使用過,在此就不再贅述.當需要傳遞多個形參時,不再需要設置parameterType參數(shù):

  • mapper
<update id="updateUserById">UPDATE user SET name = #{1}, password = #{2} WHERE id = #{0}; </update>
  • UserDAO
void updateUserById(Integer id, String name, String password) throws Exception;

傳入PO

MyBatis使用OGNL表達式解析對象屬性值:

  • mapper
<select id="selectUserByNamePassword" parameterType="com.fq.domain.User" resultType="com.fq.domain.User">SELECT *FROM userWHERE name = #{name} AND password = #{password}; </select>
  • UserDAO
User selectUserByNamePassword(User user) throws Exception;

傳入Map

  • mapper
<select id="selectUserByMap" parameterType="java.util.Map" resultType="com.fq.domain.User">SELECT *FROM userWHERE name = #{name} AND password = #{password}; </select>

#{}花括號內對應Map的key.

  • UserDAO
User selectUserByMap(Map<String, Object> map) throws Exception;

輸出映射

輸出簡單類型

  • mapper
<select id="selectUserCount" parameterType="java.lang.String" resultType="java.lang.Integer">SELECT count(*)FROM userWHERE name LIKE '%${value}%'; </select>
  • UserDAO
Integer selectUserCount(String name) throws Exception;

返回簡單類型必須保證查詢結果只有一行記錄,最終將第一個字段的值轉換為輸出類型.


輸出PO對象/列表

  • 前面已經(jīng)演示過輸出兩種類型(selectUserById/selectUserByName雖然當時使用的是原始DAO開發(fā)方法, 但mapper定義形式大同小異),因此在這兒只做簡單總結:
  • 輸出單個PO對象和輸出PO列表在mapper中定義的resultType是一樣的;
  • 輸出單個PO對象要保證SQL查詢結果為單條數(shù)據(jù),其內部使用selectOne方法調用;
  • 輸出PO列表表示查詢結果可能為多條,其內部使用selectList方法調用,接口返回值可用List<PO>/Set<PO>承載.

輸出Map

輸出PO對象完全可以改用Map輸出,字段名作key,字段值作value.

  • mapper
<select id="selectUserLikeName" resultType="java.util.Map">SELECT *FROM userWHERE name LIKE '%${value}%'; </select>
  • UserDAO
List<Map<String, Object>> selectUserLikeName(String name) throws Exception;

resultMap

resultType可將查詢結果映射為PO,但前提是PO屬性名SQL字段名必須一致,如不一致,則可通過resultMap作對應映射:

  • mapper
<resultMap id="userMap" type="com.fq.domain.User"><id column="user_id" property="id"/><result column="user_name" property="name"/><result column="user_password" property="password"/> </resultMap><select id="selectUserByName" parameterType="java.lang.String" resultMap="userMap">SELECTid user_id,name user_name,password user_passwordFROM userWHERE name = #{name}; </select> 屬性描述
<id/>表示查詢結果集的唯一標識;
<result/>表示普通結果,即PO屬性;
column表示SQL查詢出來的字段名,
property表示PO屬性.
  • UserDAO接口同前.

總結

以上是生活随笔為你收集整理的MyBatis 实践 -Mapper与DAO的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。