1. 程式人生 > 實用技巧 >java讀取一個檔案寫入另外一個檔案

java讀取一個檔案寫入另外一個檔案

Mybatis 框架快速入門

  • 概述

mybatis 是一個優秀的基於 java 的持久層框架,它內部封裝了 jdbc,使開發者只需要關注 sql 語句本身,而不需要花費精力去處理載入驅動、建立連線、建立 statement 等繁雜的過程。

mybatis 通過 xml 或註解的方式將要執行的各種 statement 配置起來,並通過 java 物件和 statement 中sql 的動態引數進行對映生成最終執行的 sql 語句,最後由 mybatis 框架執行 sql 並將結果對映為 java 物件並返回。

採用 ORM 思想解決了實體和資料庫對映的問題,對 jdbc 進行了封裝,遮蔽了 jdbc api 底層訪問細節,使我們不用與jdbc api 打交道,就可以完成對資料庫的持久化操作。為了我們能夠更好掌握框架執行的內部過程,並且有更好的體驗,下面我們將從自定義 Mybatis 框架開始來學習框架。此時我們將會體驗框架從無到有的過程體驗,也能夠很好的綜合前面階段所學的基礎。

搭建 Mybatis 開發環境

  1. 建立 maven 工程並新增 Mybatis3.4.5 的座標

  2. 編寫User實體類

  3. 編寫持久層介面 IUserDao(可以命名為 UserDao 或者 UserMapper)

    public interface IUserDao {
    List<User> findAll();
    }
  4. 編寫持久層介面的對映檔案 IUserDao.xml

    要求:

    1. 創造位置必須在resources目錄下和持久層介面在相同的包中。

    2. 名稱必須以持久層介面名稱命名檔名,副檔名是.xml

  5. 在 IUserDao.xml頁面中填寫查詢語句

    1 <?
    xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <mapper namespace="com.itheima.dao.IUserDao"> 6 <!-- 配置查詢所有操作 --> 7 <select id="findAll" resultType="com.itheima.domain.User"
    > 8 select * from user 9 </select>

  6. 編寫 SqlMapConfig.xml 配置檔案

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!DOCTYPE configuration
     3         PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
     4         "http://mybatis.org/dtd/mybatis-3-config.dtd">
     5 <configuration>
     6     <!-- 配置 mybatis 的環境 -->
     7     <environments default="mysql">
     8         <!-- 配置 mysql 的環境 -->
     9         <environment id="mysql">
    10             <!-- 配置事務的型別 -->
    11             <transactionManager type="JDBC"></transactionManager>
    12             <!-- 配置連線資料庫的資訊:用的是資料來源(連線池) -->
    13             <dataSource type="POOLED">
    14                 <property name="driver" value="com.mysql.jdbc.Driver"/>
    15                 <property name="url" value="jdbc:mysql://localhost:3306/ee50"/>
    16                 <property name="username" value="root"/>
    17                 <property name="password" value="1234"/>
    18             </dataSource>
    19         </environment>
    20     </environments>
    21     <!-- 告知 mybatis 對映配置的位置 -->
    22     <mappers>
    23         <mapper resource="com/itheima/dao/IUserDao.xml"/>
    24     </mappers>
    25 </configuration>

  7. 編寫測試類

     1 public class MybatisTest {
     2     public static void main(String[] args) throws Exception {
     3         //1.讀取配置檔案
     4         InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
     5         //2.建立 SqlSessionFactory 的構建者物件
     6         SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
     7         //3.使用構建者建立工廠物件 SqlSessionFactory
     8         SqlSessionFactory factory = builder.build(in);
     9         //4.使用 SqlSessionFactory 生產 SqlSession 物件
    10         SqlSession session = factory.openSession();
    11         //5.使用 SqlSession 建立 dao 介面的代理物件
    12         IUserDao userDao = session.getMapper(IUserDao.class);
    13         //6.使用代理物件執行查詢所有方法
    14         List<User> users = userDao.findAll();
    15         for (User user : users) {
    16             System.out.println(user);
    17         }
    18         //7.釋放資源
    19         session.close();
    20         in.close();
    21     }
    22 }

基於註解的 mybatis 使用

  1. 修改 SqlMapConfig.xml

    <!-- 告知 mybatis 對映配置的位置 -->
    <mappers>
    <mapper class="com.itheima.dao.IUserDao"/>
    </mappers>
  2. 在使用基於註解的 Mybatis 配置時,請移除 xml 的對映配置(IUserDao.xml)。

自定義 Mybatis 框架

前期準備

  1. 引入工具類XMLConfigBuilder到專案中

  2. 編寫 SqlMapConfig.xml

     1 <?xml version="1.0" encoding="UTF-8" ?>
     2 <configuration>
     3     <environments default="development">
     4         <environment id="development">
     5             <transactionManager type="JDBC"/>
     6             <dataSource type="POOLED">
     7                 <property name="driver" value="com.mysql.jdbc.Driver"></property>
     8                 <property name="url" value="jdbc:mysql:///eesy"></property>
     9                 <property name="username" value="root"></property>
    10                 <property name="password" value="1234"></property>
    11             </dataSource>
    12         </environment>
    13     </environments>
    14 </configuration>

  3. 編寫讀取配置檔案類

     1 public class Resources {
     2     /**
     3      * 用於載入 xml 檔案,並且得到一個流物件
     4      *
     5      * @param xmlPath
     6      * @return 在實際開發中讀取配置檔案:
     7      * 第一:使用類載入器。但是有要求:a 檔案不能過大。 b 檔案必須在類路徑下(classpath)
     8      * 第二:使用 ServletContext 的 getRealPath()
     9      */
    10     public static InputStream getResourceAsStream(String xmlPath) {
    11         return Resources.class.getClassLoader().getResourceAsStream(xmlPath);
    12     }
    13 }

  4. 編寫 Mapper 類

    public class Mapper {
        private String queryString;//sql
        private String resultType;//結果型別的全限定類名
        ...
        //並生成get set方法
    }
  5. 編寫 Configuration 配置類

    public class Configuration {
        private String username; //使用者名稱
        private String password;//密碼
        private String url;//地址
        private String driver;//驅動
        //map 集合 Map<唯一標識,Mapper> 用於儲存對映檔案中的 sql 標識及 sql 語句
        private Map<String, Mapper> mappers;
        
        ...
        //並生成get set方法
    }
  6. 編寫實體類

基於 XML 的自定義 mybatis 框架

  1. 編寫持久層介面和 IUserDao.xml(如上)

    • 此處我們使用的也是 mybatis 的配置檔案,所以也要把約束刪除了

  2. 編寫SqlSessionFactoryBuilder構建者類

    public class SqlSessionFactoryBuilder {
        /**
         * 根據傳入的流,實現對 SqlSessionFactory 的建立
         * @param in 它就是 SqlMapConfig.xml 的配置以及裡面包含的 IUserDao.xml 的配置
         * @return
         */
        public SqlSessionFactory build(InputStream in) {
            DefaultSqlSessionFactory factory = new DefaultSqlSessionFactory();
            //給 factory 中 config 賦值
            factory.setConfig(in);
            return factory;
        }
    }
    

      

  3. 編寫 SqlSessionFactory 介面和實現類

    public interface SqlSessionFactory {
        SqlSession openSession();
    }
    ​
    public class DefaultSqlSessionFactory implements SqlSessionFactory {
        private InputStream config = null;
    ​
        public void setConfig(InputStream config) {
            this.config = config;
        }
    ​
        @Override
        public SqlSession openSession() {
            DefaultSqlSession session = new DefaultSqlSession();
            //呼叫工具類解析 xml 檔案
            XMLConfigBuilder.loadConfiguration(session, config);
            return session;
        }
    }
    

      

  4. 編寫 SqlSession 介面和實現類

    import javax.security.auth.login.Configuration;
    import java.lang.reflect.Proxy;
    import java.sql.SQLException;
    import java.util.List;
    import java.util.concurrent.Executor;
    ​
    public interface SqlSession {
        //建立 Dao 介面的代理物件
        <T> T getMapper(Class<T> daoClass);
        //釋放資源
        void close();
    }
    ​
    public class DefaultSqlSession implements SqlSession {
        //核心配置物件
        private Configuration cfg;
    ​
        public void setCfg(Configuration cfg) {
            this.cfg = cfg;
        }
    ​
        //連線物件
        private Connection conn;
    ​
        //呼叫 DataSourceUtils 工具類獲取連線
        public Connection getConn() {
            try {
                conn = DataSourceUtil.getDataSource(cfg).getConnection();
                return conn;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    ​
        /**
         * 動態代理:
         * 涉及的類:Proxy
         * 使用的方法:newProxyInstance
         * 方法的引數:
         * ClassLoader:和被代理物件使用相同的類載入器,通常都是固定的
         * Class[]:代理物件和被代理物件要求有相同的行為。(具有相同的方法)
         * InvocationHandler:如何代理。需要我們自己提供的增強部分的程式碼
         */
        @Override
        public <T> T getMapper(Class<T> daoClass) {
            conn = getConn();
            System.out.println(conn);
            T daoProxy = (T) Proxy.newProxyInstance(daoClass.getClassLoader(), new
                    Class[]{daoClass}, new MapperProxyFactory(cfg.getMappers(), conn));
            return daoProxy;
        }//釋放資源
    ​
        @Override
        public void close() {
            try {
                System.out.println(conn);
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    ​
        //查詢所有方法
        public <E> List<E> selectList(String statement) {
            Mapper mapper = cfg.getMappers().get(statement);
            return new Executor().selectList(mapper, conn);
        }
    }
    

      

  5. 編寫用於建立 Dao 介面代理物件的類

    public class MapperProxyFactory implements InvocationHandler {
        private Map<String, Mapper> mappers;
        private Connection conn;
    ​
        public MapperProxyFactory(Map<String, Mapper> mappers, Connection conn) {
            this.mappers = mappers;
            this.conn = conn;
        }
    ​
        /**
         * 對當前正在執行的方法進行增強
         * 取出當前執行的方法名稱
         * 取出當前執行的方法所在類
         * 拼接成 key
         * 去 Map 中獲取 Value(Mapper)
         * 使用工具類 Executor 的 selectList 方法
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //1.取出方法名
            String methodName = method.getName();
            //2.取出方法所在類名
            String className = method.getDeclaringClass().getName();
            //3.拼接成 Key
            String key = className + "." + methodName;
            //4.使用 key 取出 mapper
            Mapper mapper = mappers.get(key);
            if (mapper == null) {
                throw new IllegalArgumentException("傳入的引數有誤,無法獲取執行的必要條件");
            }
            //5.建立 Executor 物件
            Executor executor = new Executor();
            return executor.selectList(mapper, conn);
        }
    }
    

      

  6. 執行測試類

    public class MybatisTest {
        public static void main(String[] args) throws Exception {
            //1.讀取配置檔案
            InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
            //2.建立 SqlSessionFactory 的構建者物件
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            //3.使用構建者建立工廠物件 SqlSessionFactory
            SqlSessionFactory factory = builder.build(in);
            //4.使用 SqlSessionFactory 生產 SqlSession 物件
            SqlSession session = factory.openSession();
            //5.使用 SqlSession 建立 dao 介面的代理物件
            IUserDao userDao = session.getMapper(IUserDao.class);
            //6.使用代理物件執行查詢所有方法
            List<User> users = userDao.findAll();
            for (User user : users) {
                System.out.println(user);
            }
            //7.釋放資源
            session.close();
            in.close();
        }
    }
    

      

基於註解方式定義 Mybatis 框架

  1. 自定義@Select 註解

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface Select {
    String value();
    }
  2. 修改持久層介面

    public interface IUserDao {
    @Select("select * from user")
    List<User> findAll();
    }
  3. 修改 SqlMapConfig.xml

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <configuration>
     3     <!-- 配置 mybatis 的環境 -->
     4     <environments default="mysql">
     5         <!-- 配置 mysql 的環境 -->
     6         <environment id="mysql">
     7             <!-- 配置事務的型別 -->
     8             <transactionManager type="JDBC"></transactionManager>
     9             <!-- 配置連線資料庫的資訊:用的是資料來源(連線池) -->
    10             <dataSource type="POOLED">
    11                 <property name="driver" value="com.mysql.jdbc.Driver"/>
    12                 <property name="url" value="jdbc:mysql://localhost:3306/ee50"/>
    13                 <property name="username" value="root"/>
    14                 <property name="password" value="1234"/>
    15             </dataSource>
    16         </environment>
    17     </environments>
    18     <!-- 告知 mybatis 對映配置的位置 -->
    19     <mappers>
    20         <mapper class="com.itheima.dao.IUserDao"/>
    21     </mappers>
    22 </configuration>

自定義 Mybatis 的設計模式說明

  1. 工廠模式(SqlSessionFactory)

    工廠模式是我們最常用的例項化物件模式了,是用工廠方法代替new操作的一種模式。著名的Jive論壇 ,就大量使用了工廠模式,工廠模式在Java程式系統可以說是隨處可見。因為工廠模式就相當於建立例項物件的new,我們經常要根據類Class生成例項物件,如A a=new A() 工廠模式也是用來建立例項物件的,所以以後new時就要多個心眼,是否可以考慮使用工廠模式,雖然這樣做,可能多做一些工作,但會給你係統帶來更大的可擴充套件性和儘量少的修改量。

  2. 代理模式(MapperProxyFactory)

    • 組成:

      • 抽象角色:通過介面或抽象類宣告真實角色實現的業務方法。

      • 代理角色:實現抽象角色,是真實角色的代理,通過真實角色的業務邏輯方法來實現抽象方法,並可以附加自己的操作。

      • 真實角色:實現抽象角色,定義真實角色所要實現的業務邏輯,供代理角色呼叫。

    • 代理模式分為靜態和動態代理

  3. 構建者模式(SqlSessionFactoryBuilder)

    建立者模式是java23種設計模式之一,英文叫Builder Pattern。其核心思想是將一個“複雜物件的構建演算法”與它的“部件及組裝方式”分離,使得構件演算法和組裝方式可以獨立應對變化;複用同樣的構建演算法可以建立不同的表示,不同的構建過程可以複用相同的部件組裝方式。

總結

基於代理 Dao 實現 CRUD 操作

  • 使用要求:

    • 持久層介面和持久層介面的對映配置必須在相同的包下

    • 持久層對映配置中 mapper 標籤的 namespace 屬性取值必須是持久層介面的全限定類名

    • SQL 語句的配置標籤<select>,<insert>,<delete>,<update>的 id 屬性必須和持久層介面的方法名相同

  • 配置檔案的細節

    • resultType 屬性:用於指定結果集的型別。

    • parameterType 屬性:用於指定傳入引數的型別。

    • sql 語句中使用#{}字元: 它代表佔位符,都是用於執行語句時替換實際的資料,具體的資料是由#{}裡面的內容決定的。

    • #{}中內容的寫法:由於資料型別是基本型別,所以此處可以隨意寫。

      • 它用的是 ognl 表示式。

      • 它是 apache 提供的一種表示式語言,全稱是:Object Graphic Navigation Language 物件圖導航語言

  • 在測試類新增測試(並把公共部分提取出來)

    public class MybastisCRUDTest {
        private InputStream in;
        private SqlSessionFactory factory;
        private SqlSession session;
        private IUserDao userDao;
    
        @Test
        public void testFindOne() {
            //6.執行操作
            User user = userDao.findById(41);
            System.out.println(user);
        }
    
        @Before//在測試方法執行之前執行
        public void init() throws Exception {
            //1.讀取配置檔案
            in = Resources.getResourceAsStream("SqlMapConfig.xml");
            //2.建立構建者物件
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            //3.建立 SqlSession 工廠物件
            factory = builder.build(in);
            //4.建立 SqlSession 物件
            session = factory.openSession();
            //5.建立 Dao 的代理物件
            userDao = session.getMapper(IUserDao.class);
        }
    
        @After//在測試方法執行完成之後執行
        public void destroy() throws Exception {
        	//實現事務提交
            session.commit();
            //7.釋放資源
            session.close();
            in.close();
        }
    }
    

      

問題擴充套件

  1. 新增使用者 id 的返回值

    新增使用者後,同時還要返回當前新增使用者的 id 值,因為 id 是由資料庫的自動增長來實現的,所以就相當於我們要在新增後將自動增長 auto_increment 的值返回。

    <insert id="saveUser" parameterType="USER">
        <!-- 配置儲存時獲取插入的 id -->
        <selectKey keyColumn="id" keyProperty="id" resultType="int">
            select last_insert_id();
        </selectKey>
        insert into user(username,birthday,sex,address)
        values(#{username},#{birthday},#{sex},#{address})
    </insert>

  2. 模糊查詢的三種方式

    <!-- 第一種 -->
    <select id="findByName" resultType="com.itheima.domain.User" parameterType="String">
        select * from user where username like #{username}
    </select>
    
     @Test
     public void testFindByName(){
         //5.執行查詢一個方法
         List<User> users = userDao.findByName("%王%");
         for(User user : users){
             System.out.println(user);
         }
     }
     //這種方法%要作為引數一起拼接傳遞進去
    <!-- 第二種 -->
    <select id="findByName" parameterType="string" resultType="com.itheima.domain.User">
        select * from user where username like '%${value}%'
    </select>
    //在上面將原來的#{}佔位符,改成了${value}。注意如果用模糊查詢的這種寫法,那麼${value}的寫法就是固定的,不能寫成其它名字。
    <!-- 第三種 -->
    <select id="findByName" parameterType="string" resultType="com.itheima.domain.User">
        select * from user where username like '%' #{username} '%'
    </select>
    //這種方法%和#{}之間要有空格

    • #{}與${}的區別

      • #{}表示一個佔位符號,自動進行 java 型別和 jdbc 型別轉換,可以有效防止 sql 注入。

      • ${}表示拼接 sql 串,e 傳入的內容拼接在 sql 中且不進行 jdbc 型別轉換,不可以有效防止 sql 注入。

Mybatis 的引數深入

parameterType 配置引數

resultType 配置結果型別

resultMap 結果型別

當查詢的資料庫的列名和實體類的屬性名稱不一致時,我們一般在sql語句上用 as 給每個欄位名起上別名 ,讓其別名和實體類的屬性名稱保持一致從而實現封裝。resultMap 標籤可以建立查詢的列名和實體類的屬性名稱不一致時建立對應關係。從而實現封裝。

在 select 標籤中使用 resultMap 屬性指定引用即可。

<!--
    type 屬性:指定實體類的全限定類名
    id 屬性:給定一個唯一標識,是給查詢 select 標籤引用用的。
-->
<resultMap type="com.itheima.domain.User" id="userMap">
    <id column="id" property="userId"/>
    <result column="username" property="userName"/>
    <result column="sex" property="userSex"/>
    <result column="address" property="userAddress"/>
    <result column="birthday" property="userBirthday"/>
</resultMap>
   <!-- id 標籤:用於指定主鍵欄位
        result 標籤:用於指定非主鍵欄位
        column 屬性:用於指定資料庫列名
        property 屬性:用於指定實體類屬性名稱 -->
<!-- 對映resultMap配置 -->
<select id="findAll" resultMap="userMap">
    select * from user
</select>

Mybatis 傳統 DAO 層開發(瞭解)

//持久層 Dao 實現類
public class UserDaoImpl implements IUserDao {
    private SqlSessionFactory factory;
​
    public UserDaoImpl(SqlSessionFactory factory) {
        this.factory = factory;
    }
​
    @Override
    public List<User> findAll() {
        SqlSession session = factory.openSession();
        List<User> users = session.selectList("com.itheima.dao.IUserDao.findAll");
        session.close();
        return users;
    }
​
    @Override
    public User findById(Integer userId) {
        SqlSession session = factory.openSession();
        User user = session.selectOne("com.itheima.dao.IUserDao.findById", userId);
        session.close();
        return user;
    }
​
    @Override
    public int saveUser(User user) {
        SqlSession session = factory.openSession();
        int res = session.insert("com.itheima.dao.IUserDao.saveUser", user);
        session.commit();
        session.close();
        return res;
    }
​
    @Override
    public int updateUser(User user) {
        SqlSession session = factory.openSession();
        int res = session.update("com.itheima.dao.IUserDao.updateUser", user);
        session.commit();
        session.close();
        return res;
    }
​
    @Override
    public int deleteUser(Integer userId) {
        SqlSession session = factory.openSession();
        int res = session.delete("com.itheima.dao.IUserDao.deleteUser", userId);
        session.commit();
        session.close();
        return res;
    }
​
    @Override
    public int findTotal() {
        SqlSession session = factory.openSession();
        int res = session.selectOne("com.itheima.dao.IUserDao.findTotal");
        session.close();
        return res;
    }
}

  

SqlMapConfig.xml配置檔案

配置內容

SqlMapConfig.xml 中配置的內容和順序

-properties(屬性)
--property
-settings(全域性配置引數)
--setting
-typeAliases(類型別名)
--typeAliase
--package
-typeHandlers(型別處理器)
-objectFactory(物件工廠)
-plugins(外掛)
-environments(環境集合屬性物件)
--environment(環境子屬性物件)
---transactionManager(事務管理)
---dataSource(資料來源)
-mappers(對映器)
--mapper
--package

properties(屬性)

在使用 properties 標籤配置時,我們可以採用兩種方式指定屬性配置。

第一種

<properties>
<property name="jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="jdbc.url" value="jdbc:mysql://localhost:3306/eesy"/>
<property name="jdbc.username" value="root"/>
<property name="jdbc.password" value="1234"/>
</properties>

第二種

在 classpath 下定義 db.properties 檔案

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/eesy
jdbc.username=root
jdbc.password=1234

properties 標籤配置

<!-- 配置連線資料庫的資訊
resource 屬性:用於指定 properties 配置檔案的位置,要求配置檔案必須在類路徑下
-->
<properties url="file:///D:/IdeaProjects/day02_eesy_01mybatisCRUD/src/main/resources/jdbcConfig.properties"></properties>

此時我們的 dataSource 標籤就變成了引用上面的配置

<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>

typeAliases(類型別名)

自定義別名

在 SqlMapConfig.xml 中配置:
<typeAliases>
    <!-- 單個別名定義 -->
    <typeAlias alias="user" type="com.itheima.domain.User"/>
    <!-- 批量別名定義,掃描整個包下的類,別名為類名(首字母大寫或小寫都可以) -->
    <package name="com.itheima.domain"/>
    <package name="其它包"/>
</typeAliases>

mappers(對映器)

1.使用相對於類路徑的資源
<mapper resource="com/itheima/dao/IUserDao.xml" />
2.使用 mapper 介面類路徑
此種方法要求 mapper 介面名稱和 mapper 對映檔名稱相同,且放在同一個目錄中。
<mapper class="com.itheima.dao.UserDao"/>
3.註冊指定包下的所有 mapper 介面
<package name="cn.itcast.mybatis.mapper"/>

Mybatis 的動態 SQL 語句

 1 <!-- 1. 動態 SQL 之<if>標籤-->
 2 <select id="findByUser" resultType="user" parameterType="user">
 3     select * from user where 1=1
 4     <if test="username!=null and username != '' ">
 5         and username like #{username}
 6     </if>
 7     <if test="address != null">
 8     and address like #{address}
 9     </if>
10 </select>
11 注意:要注意 where 1=1 的作用~!
12 13 <!-- 2. 動態 SQL 之<where>標籤-->
14 <!-- 根據使用者資訊查詢 -->
15 <select id="findByUser" resultType="user" parameterType="user">
16     <include refid="defaultSql"></include>
17     <where>
18         <if test="username!=null and username != '' ">
19             and username like #{username}
20         </if>
21         <if test="address != null">
22             and address like #{address}
23         </if>
24     </where>
25 </select>
26 27 <!-- 3. 動態 SQL 之<foreach>標籤-->
28 <!-- 查詢所有使用者在 id 的集合之中 -->
29 <select id="findInIds" resultType="user" parameterType="queryvo">
30     <!-- select * from user where id in (1,2,3,4,5); -->
31     <include refid="defaultSql"></include>
32     <where>
33         <if test="ids != null and ids.size() > 0">
34             <foreach collection="ids" open="id in ( " close=")" item="uid"
35                      separator=",">
36                 #{uid}
37             </foreach>
38         </if>
39     </where>
40 </select>
41         SQL 語句:
42         select 欄位 from user where id in (?)
43 <foreach>標籤用於遍歷集合,它的屬性:
44 collection:代表要遍歷的集合元素,注意編寫時不要寫#{}
45 open:代表語句的開始部分
46 close:代表結束部分
47 item:代表遍歷集合的每個元素,生成的變數名
48 sperator:代表分隔符
49 50 <!-- 4. Mybatis 中簡化編寫的 SQL 片段-->
51 <!-- 抽取重複的語句程式碼片段 --> 
52 <sql id="defaultSql">
53     select * from user
54 </sql>
55

Mybatis 多表查詢

一對一(一對多)

  1. 方式一:如果查詢出來的欄位包括第一個pojo類(如Account)的所有的屬性和第二個pojo類(User)的部分屬性的話,可以新建第三個pojo類(AccountUser)使其繼承Account類,並在類中定義查詢出來的剩餘欄位,返回值型別 returnType的值設定為 AccountUser 型別,這樣就可以接收所有欄位了。

  2. 方式二:使用 resultMap,定義專門的 resultMap 用於對映一對一查詢結果。

    1. 在 Account 類中加入 User 類的物件作為 Account 類的一個屬性。

    2. 重新定義 AccountDao.xml 檔案

       1 <?xml version="1.0" encoding="UTF-8"?>
       2 <!DOCTYPE mapper
       3         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
       4         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
       5 <mapper namespace="com.itheima.dao.IAccountDao">
       6     <!-- 建立對應關係 -->
       7     <resultMap type="account" id="accountMap">
       8         <id column="aid" property="id"/>
       9         <result column="uid" property="uid"/>
      10         <result column="money" property="money"/>
      11         <!-- 它是用於指定從表方的引用實體屬性的 -->
      12         <association property="user" javaType="user">
      13             <id column="id" property="id"/>
      14             <result column="username" property="username"/>
      15             <result column="sex" property="sex"/>
      16             <result column="birthday" property="birthday"/>
      17             <result column="address" property="address"/>
      18         </association>
      19     </resultMap>
      20     <select id="findAll" resultMap="accountMap">
      21         select u.*,a.id as aid,a.uid,a.money from account a,user u where a.uid =u.id;
      22     </select>
      23 </mapper>

一對多

  1. 在 User 類中加入 List<Account>作為 User 類的一個屬性。

  2. 重新定義 UserDao.xml 檔案

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!DOCTYPE mapper
     3         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     4         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
     5 <mapper namespace="com.itheima.dao.IUserDao">
     6     <resultMap type="user" id="userMap">
     7         <id column="id" property="id"></id>
     8         <result column="username" property="username"/>
     9         <result column="address" property="address"/>
    10         <result column="sex" property="sex"/>
    11         <result column="birthday" property="birthday"/>
    12         <!-- collection 是用於建立一對多中集合屬性的對應關係
    13         ofType 用於指定集合元素的資料型別
    14         -->
    15         <collection property="accounts" ofType="account">
    16             <id column="aid" property="id"/>
    17             <result column="uid" property="uid"/>
    18             <result column="money" property="money"/>
    19         </collection>
    20     </resultMap>
    21     <!-- 配置查詢所有操作 -->
    22     <select id="findAll" resultMap="userMap">
    23         select u.*,a.id as aid ,a.uid,a.money from user u left outer join account a on u.id =a.uid
    24     </select>
    25 </mapper> 
    26 collection:部分定義了使用者關聯的賬戶資訊。表示關聯查詢結果集
    27 property="accList":關聯查詢的結果集儲存在 User 物件的上哪個屬性。
    28 ofType="account":指定關聯查詢的結果集中的物件型別即List中的物件型別。此處可以使用別名,也可以使用全限定名。

多對多

Mybatis 延遲載入策略

何為延遲載入?

延遲載入:就是在需要用到資料時才進行載入,不需要用到資料時就不載入資料。延遲載入也稱懶載入.

好處:先從單表查詢,需要時再從關聯表去關聯查詢,大大提高資料庫效能,因為查詢單表要比關聯查詢多張錶速度要快。

壞處:因為只有當需要用到資料時,才會進行資料庫查詢,這樣在大批量資料查詢時,因為查詢工作也要消耗時間,所以可能造成使用者等待時間變長,造成使用者體驗下降。

使用 assocation 實現延遲載入

賬號持久層和對映檔案

public interface IAccountDao {
//查詢所有賬戶,同時獲取賬戶的所屬使用者名稱稱以及它的地址資訊
List<Account> findAll();
}
<mapper namespace="com.itheima.dao.IAccountDao">
<!-- 建立對應關係 -->
<resultMap type="account" id="accountMap">
<id column="aid" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/>
<!-- 它是用於指定從表方的引用實體屬性的 -->
<!-- select: 填寫我們要呼叫的 select 對映的 id -->
<!-- column : 填寫我們要傳遞給 select 對映的引數 -->
<association property="user" javaType="user"
select="com.itheima.dao.IUserDao.findById"
column="uid">
</association>
</resultMap>
<select id="findAll" resultMap="accountMap">
select * from account
</select>
</mapper>

使用者持久層和對映檔案

public interface IUserDao {
//根據 id 查詢
User findById(Integer userId);
}
<mapper namespace="com.itheima.dao.IUserDao">
<!-- 根據 id 查詢 -->
<select id="findById" resultType="user" parameterType="int">
select * from user where id = #{uid}
</select>
</mapper>

要在 Mybatis 的配置檔案 SqlMapConfig.xml 檔案中新增延遲載入的配置

<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>

使用 Collection 實現延遲載入

與使用 assocation 實現延遲載入,都是在標籤內新增select和column屬性使其進行對映

Mybatis 快取

像大多數的持久化框架一樣,Mybatis 也提供了快取策略,通過快取策略來減少資料庫的查詢次數,從而提高效能。Mybatis 中快取分為一級快取,二級快取

Mybatis 一級快取

一級快取是 SqlSession 範圍的快取,當呼叫 SqlSession 的修改,新增,刪除,commit(),close()等方法時,就會清空一級快取。

Mybatis 二級快取

二級快取是 mapper 對映級別的快取,多個 SqlSession 去操作同一個 Mapper 對映的 sql 語句,多個SqlSession 可以共用二級快取,二級快取是跨 SqlSession 的。

二級快取的開啟與關閉

第一步:在 SqlMapConfig.xml 檔案開啟二級快取

<settings>
<!-- 開啟二級快取的支援 -->
<setting name="cacheEnabled" value="true"/>
</settings>
因為 cacheEnabled 的取值預設就為 true,所以這一步可以省略不配置。為 true 代表開啟二級快取;為
false 代表不開啟二級快取。

第二步:配置相關的 Mapper 對映檔案

<cache>標籤表示當前這個 mapper 對映將使用二級快取,區分的標準就看 mapper 的 namespace 值。
<mapper namespace="com.itheima.dao.IUserDao">
<!-- 開啟二級快取的支援 -->
<cache></cache>
</mapper>

第三步:配置 statement 上面的 useCache 屬性

<!-- 根據 id 查詢 -->
<select id="findById" resultType="user" parameterType="int" useCache="true">
select * from user where id = #{uid}
</select>
將 UserDao.xml 對映檔案中的<select>標籤中設定 useCache=”true”代表當前這個 statement 要使用二級快取,如果不使用二級快取可以設定為 false。
注意:針對每次查詢都需要最新的資料 sql,要設定成 useCache=false,禁用二級快取。

Mybatis 註解開發

mybatis 的常用註解說明

@Insert:實現新增
@Update:實現更新
@Delete:實現刪除
@Select:實現查詢
@Result:實現結果集封裝
@Results:可以與@Result 一起使用,封裝多個結果集
@ResultMap:實現引用@Results 定義的封裝
@One:實現一對一結果集封裝
@Many:實現一對多結果集封裝
@SelectProvider: 實現動態 SQL 對映
@CacheNamespace:實現註解二級快取的使用

使用註解方式開發持久層介面

public interface IUserDao {
    //查詢所有使用者
    @Select("select * from user")
    @Results(id = "userMap",
            value = {
                    @Result(id = true, column = "id", property = "userId"),
                    @Result(column = "username", property = "userName"),
                    @Result(column = "sex", property = "userSex"),
                    @Result(column = "address", property = "userAddress"),
                    @Result(column = "birthday", property = "userBirthday")
            })
    List<User> findAll();
​
    //根據 id查詢一個使用者
    @Select("select * from user where id = #{uid} ")
    @ResultMap("userMap")
    User findById(Integer userId);
​
    //儲存操作
    @Insert("insert into user(username, sex, birthday, address)values(# {username},#{sex},#{birthday},#{address})")
    @SelectKey(keyColumn = "id", keyProperty = "id", resultType = Integer.class, before =false, statement = {"select last_insert_id()"})
    int saveUser(User user);
​
    //更新操作
    @Update("update user set username=#{username}, address =#{address}, sex =#{sex}, birthday =#{birthday}where id =#{id}")
    int updateUser(User user);
​
    //刪除使用者
    @Delete("delete from user where id = #{uid} ")
    int deleteUser(Integer userId);
​
    //查詢使用聚合函式
    @Select("select count(*) from user ")
    int findTotal();
​
    //模糊查詢
    @Select("select * from user where username like #{username} ")
    List<User> findByName(String name);
}

  

編寫 SqlMapConfig 配置檔案

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE configuration
 3         PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 4         "http://mybatis.org/dtd/mybatis-3-config.dtd">
 5 <configuration>
 6     <!-- 配置 properties 檔案的位置 -->
 7     <properties resource="jdbcConfig.properties"></properties>
 8     <!-- 配置別名的註冊 -->
 9     <typeAliases>
10         <package name="com.itheima.domain"/>
11     </typeAliases>
12     <!-- 配置環境 -->
13     <environments default="mysql">
14         <!-- 配置 mysql 的環境 -->
15         <environment id="mysql">
16             <!-- 配置事務的型別是 JDBC -->
17             <transactionManager type="JDBC"></transactionManager>
18             <!-- 配置資料來源 -->
19             <dataSource type="POOLED">
20                 <property name="driver" value="${jdbc.driver}"/>
21                 <property name="url" value="${jdbc.url}"/>
22                 <property name="username" value="${jdbc.username}"/>
23                 <property name="password" value="${jdbc.password}"/>
24             </dataSource>
25         </environment>
26     </environments>
27     <!-- 配置對映資訊 -->
28     <mappers>
29         <!-- 配置 dao 介面的位置,它有兩種方式
30         第一種:使用 mapper 標籤配置 class 屬性
31         第二種:使用 package 標籤,直接指定 dao 介面所在的包
32         -->
33         <package name="com.itheima.dao"/>
34     </mappers>
35 </configuration>

使用註解實現複雜關係對映開發

  1. 一對一、一對多

    @One 註解(一對一)
    代替了<assocation>標籤,是多表查詢的關鍵,在註解中用來指定子查詢返回單一物件。
    @One 註解屬性介紹:
    select 指定用來多表查詢的 sqlmapper
    fetchType 會覆蓋全域性的配置引數 lazyLoadingEnabled。。
    使用格式:@Result(column=" ",property="",one=@One(select=""))
    @Many 註解(多對一)
    代替了<Collection>標籤,是多表查詢的關鍵,在註解中用來指定子查詢返回物件集合。
    注意:聚集元素用來處理“一對多”的關係。需要指定對映的 Java 實體類的屬性,屬性的 javaType (一般為 ArrayList)但是註解中可以不定義;
    使用格式: @Result(property="",column="",many=@Many(select=""))
  2. 採用延遲載入的方式查詢

    1.一對一
    @Result(column="uid",
    property="user",
    one=@One(select="com.itheima.dao.IUserDao.findById",
    fetchType=FetchType.LAZY) )
    2.一對多
    @Result(column="id",
    property="accounts",
    many=@Many(select="com.itheima.dao.IAccountDao.findByUid",
    fetchType=FetchType.LAZY) )
  3. 在持久層介面中使用註解配置二級快取

    @CacheNamespace(blocking = true)//mybatis 基於註解方式實現配置二級快取
    public interface IUserDao {
    }

Mybatis逆向工程(瞭解)

https://www.cnblogs.com/xqz0618/p/javaweb05.html