1. 程式人生 > >Mybatis快速入門——Mybatis學習總結(一)

Mybatis快速入門——Mybatis學習總結(一)

一.Mybatis介紹


MyBatis 本是apache的一個開源專案iBatis, 2013年11月遷移到Github。
MyBatis是一個優秀的持久層框架,它對jdbc的操作資料庫的過程進行封裝,使開發者只需要關注 SQL 本身。
Mybatis通過xml或註解的方式將要執行的各種statement(statement、preparedStatemnt、CallableStatement)配置起來,並通過java物件和statement中的sql進行對映生成最終執行的sql語句,最後由mybatis框架執行sql並將結果對映成java物件並返回。

二. Mybatis框架圖

三. 入門專案實踐

3.1 環境搭建







依照上述方法加入 junit單元測試包, mysql 或者 oracle 連線啟動包 ,就可以了 。

3.2 加入配置檔案
3.2.1 log4j.properties  

        log4j.appender.stdout=org.apache.log4j.ConsoleAppender  
        log4j.appender.stdout.Target=System.err  
        log4j.appender.stdout.layout=org.apache.log4j.PatternLayout  
        log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n  
        ### direct messages to file mylog.log ###  
        log4j.appender.file=org.apache.log4j.FileAppender  
        log4j.appender.file.File=G:/Log4j_log/MyBatis_Base_log  
        log4j.appender.file.layout=org.apache.log4j.PatternLayout  
        log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n  
        ### set log levels - for more verbose logging change 'info' to 'debug' ###  
        log4j.rootLogger=debug, stdout  

3.2.2 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">
            <environment id="development">
                <!-- 使用jdbc事務管理 -->
                <transactionManager type="JDBC"/>
                <!-- 資料庫連線池 -->
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url"
                              value="jdbc:mysql://localhost:3306/mybatis_base?characterEncoding=utf-8"/>
                    <property name="username" value="root"/>
                    <property name="password" value="root"/>
                </dataSource>
            </environment>
        </environments>
        <mappers>
            <mapper resource="com/tzq/batis/slqmap/User.xml"/>
        </mappers>
    </configuration>
3.3 建立pojo

pojo類作為mybatis進行sql對映使用,po類通常與資料庫表對應。

資料庫表

DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL COMMENT '下單使用者id',
  `number` varchar(32) NOT NULL COMMENT '訂單號',
  `createtime` datetime NOT NULL COMMENT '建立訂單時間',
  `note` varchar(100) DEFAULT NULL COMMENT '備註',
  PRIMARY KEY (`id`),
  KEY `FK_orders_1` (`user_id`),
  CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

User.java

    package com.tzq.batis.pojo;

import java.io.Serializable;
import java.util.Date;

public class User implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private Integer id;
    private String username;// 使用者姓名
    private String sex;// 性別
    private Date birthday;// 生日
    private String address;// 地址

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    @Override
    public String toString() {
        return "User [id=" + id + ", username=" + username + ", sex=" + sex
                + ", birthday=" + birthday + ", address=" + address + "]";
    }
}
3.4 建立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">
<!-- namespace:名稱空間,用於隔離sql,已經當 id 有重新命名時 ,區分的標識 -->
<mapper namespace="test">
</mapper>
3.5 實現根據id查詢使用者

在user.xml中新增select標籤,編寫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">
<!-- namespace:名稱空間,用於隔離sql,已經當 id 有重新命名時 ,區分的標識 -->
<mapper namespace="test">

    <!-- id:statement的id 或者叫做sql的id-->
    <!-- parameterType:宣告輸入引數的型別 -->
    <!-- resultType:宣告輸出結果的型別,應該填寫pojo的全路徑 -->
    <!-- #{}:輸入引數的佔位符,相當於jdbc的? -->
    <select id="queryUserById" parameterType="int"
        resultType="cn.itcast.mybatis.pojo.User">
        SELECT * FROM `user` WHERE id  = #{id}
    </select>
</mapper>
3.6 測試程式:
public class MybatisTest {
    private SqlSessionFactory sqlSessionFactory = null;

    @Before
    public void init() throws Exception {
        // 1. 建立SqlSessionFactoryBuilder物件
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();

        // 2. 載入SqlMapConfig.xml配置檔案
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");

        // 3. 建立SqlSessionFactory物件
        this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
    }

    @Test
    public void testQueryUserById() throws Exception {
        // 4. 建立SqlSession物件
        SqlSession sqlSession = sqlSessionFactory.openSession();

        // 5. 執行SqlSession物件執行查詢,獲取結果User
        // 第一個引數是User.xml的statement的id,第二個引數是執行sql需要的引數;
        Object user = sqlSession.selectOne("queryUserById", 1);

        // 6. 列印結果
        System.out.println(user);

        // 7. 釋放資源
        sqlSession.close();
    }
}

執行結果

更多sql 操作的 user.xml 程式碼

    <!-- 寫sql語句   , namespace 表示當id 在 另一個 xml map檔案中有一樣的名字是 , 可以通過它來判斷是哪一個-->
<mapper namespace="com.tzq.batis.mapperdao.UserMapperDao">
    <!--  #{}是 mybatis 裡的萬用字元    resultType 代表 執行後的結果型別   parameterType 代表 下面萬用字元的屬性型別-->
    <!-- 通過ID查詢-->
    <select id="findByid" resultType="com.tzq.batis.pojo.User" parameterType="Integer">
        select * from user where id = #{VALUE }
    </select>

    <!--  根據使用者名稱模糊查詢資料
          #{}  表示佔位符      #{} == ?    轉換為 sql 會  給 #{} 的外出加上  ''  單引號
          ${}  表示  字串拼接     拼接不會加單引號
    -->
    <select id="findUserByName" resultType="com.tzq.batis.pojo.User" parameterType="String">
        <!--  select * from user where username like "%"#{可以隨便起名}"%"      與 下面語句一樣的效果  -->
        select * from user where username like '%${value}%'
    </select>

    <!--  新增使用者-->
    <insert id="insertUser" parameterType="com.tzq.batis.pojo.User">
        <selectKey resultType="integer" keyProperty="id" order="AFTER">
            select LAST_INSERT_ID()
        </selectKey>
        insert into user
        (username , sex) values (#{username},#{sex})
    </insert>

    <!--  更新使用者-->
    <update id="updateUser" parameterType="com.tzq.batis.pojo.User">
        update user SET username = #{username} where id = #{id}
    </update>
    <!-- 刪除使用者 -->
    <delete id="deleteUser" parameterType="com.tzq.batis.pojo.User">
        delete FROM user where id = #{id}
    </delete>
</mapper>  

對應的java程式碼


        public class TestUserMybatis {

        /*
        獲取session
         */
        public SqlSession getSqlSession() throws IOException {
            //載入核心配置檔案
            String resource = "sqlMapConfig.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            //建立SqlSessionFactory
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            //建立sqlSession
            SqlSession sqlSession = sqlSessionFactory.openSession();
            return sqlSession;
        }

        /*
        通過了ID 查詢資料
         */
        @Test
        public void testSelect() throws IOException {
            SqlSession sqlSession = getSqlSession();
            //執行sql語句  ,表示查詢一個
            User user = sqlSession.selectOne("com.tzq.batis.mapperdao.UserMapperDao.findByid", 1);
            System.out.println(user.toString());
            sqlSession.close();
        }

        /*
        根據使用者名稱模糊查詢資料
         */
        @Test
        public void testFindDimName() throws IOException {
            SqlSession sqlSession = getSqlSession();
            //執行sql語句
            List<User> list = sqlSession.selectList("test.findUserByName", "五");
            for (User user : list) {
                System.out.println(user.toString());
            }
            sqlSession.close();
        }

        /*
        新增使用者
         */
        @Test
        public void testInsertUser() throws IOException {
            SqlSession sqlSession = getSqlSession();
            //執行sql語句
            User user = new User();
            user.setUsername("李四");
            user.setSex("男");

            int insert = sqlSession.insert("test.insertUser", user);
            sqlSession.commit();
            sqlSession.close();

            System.out.println(user.getId());
        }

        /*
      修改使用者
       */
        @Test
        public void testUpdateUserById() throws IOException {
            SqlSession sqlSession = getSqlSession();
            //執行sql語句

            User user = new User();
            user.setId(29);
            user.setUsername("張三");

            sqlSession.update("updateUser", user);
            sqlSession.commit();
            sqlSession.close();
        }

        /*
    刪除使用者
     */
        @Test
        public void testDeleteUserById() throws IOException {
            SqlSession sqlSession = getSqlSession();
            //執行sql語句

            User user = new User();
            user.setId(29);

            sqlSession.update("deleteUser", user);
            sqlSession.commit();
            sqlSession.close();
        }


    }
3.7 小結
3.7.1 #{}和${}
#{}表示一個佔位符號,通過#{}可以實現preparedStatement向佔位符中設定值,自動進行java型別和jdbc型別轉換。#{}可以有效防止sql注入。 #{}可以接收簡單型別值或pojo屬性值。 如果parameterType傳輸單個簡單型別值,#{}括號中可以是value或其它名稱。

sql{}可以將parameterType 傳入的內容拼接在sql中且不進行jdbc型別轉換, pojoparameterType{}括號中只能是value。

3.7.2. parameterType和resultType

parameterType:指定輸入引數型別,mybatis通過ognl從輸入物件中獲取引數值拼接在sql中。
resultType:指定輸出結果型別,mybatis將sql查詢結果的一行記錄資料對映為resultType指定型別的物件。如果有多條資料,則分別進行對映,並把物件放到容器List中

3.7.3. selectOne和selectList

selectOne查詢一條記錄,如果使用selectOne查詢多條記錄則丟擲異常:
org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 3
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:70)
selectList可以查詢一條或多條記錄。

3.8 Dao開發

3.8.1傳統Dao的開發

Dao介面


    public interface UserDao {
    public User selectUserById(Integer id);
}

Dao介面的實現類

public class UserDaoImpl implements UserDao {
    private SqlSessionFactory sqlSessionFactory;

    public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
    }

    @Override
    public User selectUserById(Integer id) {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        User user = sqlSession.selectOne("findByid", id);
        return user;
    }
}

junit 測試類

public class TestUserDao {
    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void before() throws Exception {
        //載入核心配置檔案
        String resource = "sqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //建立SqlSessionFactory
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }


    /**
     * Method: TestDao()
     */
    @Test
    public void testTestDao() throws Exception {
        UserDao dao = new UserDaoImpl(sqlSessionFactory);
        User user = dao.selectUserById(10);
        System.out.println(user.getUsername());
    }


} 

3.9 重量級嘉賓登場 —— Mapper動態代理方式

3.9.1 開發規範

Mapper介面開發方法只需要程式設計師編寫Mapper介面(相當於Dao介面),由Mybatis框架根據介面定義建立介面的動態代理物件,代理物件的方法體同上邊Dao介面實現類方法。

#代理的介面程式碼:

    public interface UserMapperDao {
    /**
         * Mapper 動態代理方法
         * 只要實現了下面的四個原則 , 就不用寫daoImpl 了
         * Created by MyPC on 2017/8/19.
         */
        /*
        四個原則
        1.介面的方法名與  Mapper.xml 中的 id 名 一樣
        2.返回值型別與Mapper.xml檔案中返回值型別一致
        3.方法的 輸入引數 型別要與 Mapper.xml 的一致
        4.Mapper.xml名稱空間繫結這個介面全路徑名
         */
        public User findByid(Integer id);

    }
#junit測試類
    public class TestUserMapperDao {

        @Test
        public void testSelectUserById() throws IOException {
            //載入核心配置檔案
            String resource = "sqlMapConfig.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            //建立SqlSessionFactory
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            //建立sqlSession
            SqlSession sqlSession = sqlSessionFactory.openSession();

            UserMapperDao dao = sqlSession.getMapper(UserMapperDao.class);
            User user = dao.findByid(10);
            System.out.println(user.toString());

        }

    }

官網推薦使用 動態代理的方式 , 當然您可以根據自己的需求去寫。

寫的不好還望看見的兄弟不要嘲笑。