MyBatis 學(xué)習(xí)筆記(一)MyBatis的簡(jiǎn)介與使用以及與其他ORM框架的比較

什么是MyBatis

MyBatis 前身是Apache基金會(huì)的開(kāi)源項(xiàng)目iBatis,在2010年該項(xiàng)目脫離Apache基金會(huì)并正式更名為MyBatis,在2013年11月,MyBatis遷移到了GitHub。
MyBatis 是一個(gè)輕量級(jí)的,半自動(dòng)的持久化(ORM)框架, 其通過(guò)XML映射配置文件或者注解來(lái)配置和映射原生類(lèi)型,接口和Java的POJO(Plain Old Java Objects,普通老式Java對(duì)象)為數(shù)據(jù)庫(kù)中的記錄。之所以是半自動(dòng)化的框架,是因?yàn)槠洳荒芟馠ibernate一樣實(shí)現(xiàn)自動(dòng)生成SQL,其需要用戶(hù)手動(dòng)編寫(xiě)SQL語(yǔ)句。方便用戶(hù)對(duì)SQL語(yǔ)句進(jìn)行優(yōu)化,適用于大數(shù)據(jù)量,高并發(fā)場(chǎng)景。
MyBatis 是一塊比較容易上手的框架,使用者只需要通過(guò)簡(jiǎn)單的學(xué)習(xí)即可掌握其常用特性。

為什么要使用MyBatis

使用MyBatis訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)

首先在pom文件中引入依賴(lài)

       <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>

正如前面所說(shuō)MyBatis 是一個(gè)半自動(dòng)持久化框架。所以,需要我們自己來(lái)維護(hù)sql 語(yǔ)句,編寫(xiě)sql語(yǔ)句的xml文件叫做映射文件。在此處,我建立了一個(gè)StudentMapper.xml 文件來(lái)維護(hù)sql 語(yǔ)句。

<mapper namespace="com.jay.mapper.StudentMapper">
    <resultMap id="BaseColumn" type="com.jay.entity.Student">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="age" column="age"/>
    </resultMap>
     <select id="selectByName" resultMap="BaseColumn">
        select id,name,age from student where name LIKE '%'#{name}'%'
    </select>
</mapper>

上面的sql語(yǔ)句表示的意思是通過(guò)學(xué)生名稱(chēng)來(lái)模糊匹配學(xué)生

public interface StudentMapper {

    /**
     * @param name
     * @return
     */
    List<Student> selectByName(@Param("name") String name);
}

維護(hù)完映射文件和對(duì)應(yīng)的接口之后,我們還需要一個(gè)XML配置文件來(lái)對(duì)MyBatis進(jìn)行一些核心設(shè)置,包括獲取數(shù)據(jù)庫(kù)連接實(shí)例的數(shù)據(jù)源(DataSource)和決定事務(wù)作用域和控制方式的事務(wù)管理器(TransactionManager)以及SQL映射文件的位置信息等。本節(jié)所使用的配置如下:

<configuration>
    <!--加載配置文件->jdbc.properties 數(shù)據(jù)庫(kù)文件 -->
    <properties resource="jdbc.properties"/>

    <!-- 設(shè)置一個(gè)默認(rèn)的連接環(huán)境信息 -->
    <environments default="development">

        <!--連接環(huán)境信息,取一個(gè)任意唯一的名字 -->
        <environment id="development">
            <!-- mybatis使用jdbc事務(wù)管理方式 -->
            <transactionManager type="JDBC"/>
            <!-- mybatis使用連接池方式來(lái)獲取連接 -->
            <dataSource type="POOLED">
                <!-- 配置與數(shù)據(jù)庫(kù)交互的4個(gè)必要屬性 -->
                <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="xml/StudentMapper.xml"/>
    </mappers>
</configuration>

到此,MyBatis所需的環(huán)境就配置好了,接下來(lái)我們將MyBatis跑起來(lái)。測(cè)試代碼如下

    private SqlSessionFactory sqlSessionFactory;
    @Before
    public void setUp() {
        String resource = "chapter1/mybatis-cfg.xml";
        try {
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, "development");
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void mybatisTest() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> studentList = mapper.selectByName("點(diǎn)點(diǎn)");
        if (studentList != null) {
            System.out.println("----->"+studentList.get(0).toString());
        }
        sqlSession.commit();
        sqlSession.close();
    }

如上測(cè)試代碼,首先,我們根據(jù)配置文件得到文件流,然后通過(guò)SqlSessionFactoryBuilder工廠(chǎng)類(lèi)構(gòu)造器得到SqlSessionFactory,再通過(guò)SqlSessionFactory工廠(chǎng)類(lèi)得到SqlSession。然后根據(jù)SqlSession的getMapper()方法得到需要執(zhí)行的mapper。得到之后調(diào)用相應(yīng)的方法得到結(jié)果。
運(yùn)行結(jié)果如下:
在這里插入圖片描述

使用JDBC訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)

現(xiàn)在我們使用原生的JDBC來(lái)操作數(shù)據(jù)庫(kù),主要流程有以下幾個(gè):1. 加載數(shù)據(jù)庫(kù)驅(qū)動(dòng),2. 連接數(shù)據(jù)庫(kù),3,通過(guò)PreparedStatement執(zhí)行sql得到ResultSet,4,對(duì)ResultSet 進(jìn)行處理。流程固定。

public class JdbcTest {
    public static void main(String[] args) {
        String driver = "com.mysql.jdbc.Driver";
        String url = "jdbc:mysql://localhost:3306/mybatisdemo";
        String userName = "root";
        String password = "admin";

        Connection conn = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;

        try {
            Class.forName(driver);
            conn = DriverManager.getConnection(url, userName, password);

            String sql = "select id,name,age from student where name LIKE ?";
            statement = conn.prepareStatement(sql);
            statement.setString(1, "%點(diǎn)點(diǎn)%");
            resultSet = statement.executeQuery();
            List<Student> studentList = new ArrayList<Student>();
            if (resultSet != null) {
                while (resultSet.next()) {
                    Student student = new Student();
                    student.setId(resultSet.getInt("id"));
                    student.setName(resultSet.getString("name"));
                    student.setAge(resultSet.getInt("age"));
                    studentList.add(student);
                }
            }
  			System.out.println("----->執(zhí)行的sql={}"+sql);
            System.out.println("----->resultSet={}"+studentList.get(0).toString());
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                if (statement != null) {
                    statement.close();
                }
                if (conn != null) {
                    conn.close();

                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }
}

代碼比較簡(jiǎn)單,執(zhí)行結(jié)果如下:
在這里插入圖片描述
上面的代碼的步驟比較多,但是核心步驟只有兩步,分別是執(zhí)行SQL和處理查詢(xún)結(jié)果。從開(kāi)發(fā)人員的角度來(lái)說(shuō),我們只關(guān)心這兩個(gè)步驟。原生的JDBC的缺點(diǎn)主要有如下幾點(diǎn):

  1. 每次為了執(zhí)行某個(gè)SQL需要寫(xiě)很多額外的代碼,比如加載驅(qū)動(dòng),創(chuàng)建數(shù)據(jù)庫(kù)連接,代碼冗余。
  2. 將SQL寫(xiě)在代碼中,如果要改動(dòng)SQL,就需要到代碼中進(jìn)行修改,這樣做不合適,因?yàn)楦膭?dòng)了Java代碼就需要重新編譯Java文件,在打包發(fā)布,同時(shí)將SQL和Java代碼混在一起,會(huì)降低代碼的可讀性,不利于維護(hù)。
  3. 關(guān)于執(zhí)行結(jié)果的處理,需要手動(dòng)的將數(shù)據(jù)從ResultSet中取出,并設(shè)置到我們需要的對(duì)象中,如果屬性過(guò)多,用這種方式處理會(huì)非常繁瑣。
  4. 每次都要手動(dòng)管理數(shù)據(jù)庫(kù)連接,使用好之后又要手動(dòng)關(guān)閉。

MyBatis VS JDBC

首先我們來(lái)看看MyBatis訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)的過(guò)程

  1. 讀取配置文件
  2. 創(chuàng)建SqlSessionFactoryBuilder對(duì)象
  3. 通過(guò)SqlSessionFactoryBuilder創(chuàng)建SqlSessionFactory對(duì)象
  4. 通過(guò)SqlSessionFactory創(chuàng)建SqlSession
  5. 為Dao 接口生成代理類(lèi)
  6. 調(diào)用接口方法訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)
    需要注意的是,在MyBatis中SqlSessionFactoryBuilder 和 SqlSessionFactory 以及 SqlSession 等對(duì)象的作用域和生命周期是不一樣的。
    SqlSessionFactoryBuilder
    這個(gè)類(lèi)可以被實(shí)例化,使用和丟棄,一旦創(chuàng)建了SqlSessionFactory,就不需要它了,所以,SqlSessionFactoryBuilder實(shí)例的最佳作用域是方法作用域(也就是局部方法變量)
    SqlSessionFactory
    SqlSessionFactory一旦被創(chuàng)建就應(yīng)該在應(yīng)用的運(yùn)行期間一直存在,沒(méi)有任何理由丟棄它或重新創(chuàng)建另外一個(gè)實(shí)例,使用SqlSessionFactory的最佳實(shí)踐食雜應(yīng)用運(yùn)行期間不要重復(fù)創(chuàng)建多起,多次重建SqlSessionFactory被視為一種代碼”壞味道“。因此SqlSessionFactory的最佳作用域是應(yīng)用作用域,有很多方法可以做到,最簡(jiǎn)單的就是使用單例模式或者靜態(tài)單例模式。
    SqlSession
    每個(gè)線(xiàn)程都應(yīng)該有它自己的SqlSession實(shí)例,SqlSession的實(shí)例不是線(xiàn)程安全的,因此是不能被共享的,所有它的最佳的作用域是請(qǐng)求或方法作用域,絕對(duì)不能講SqlSession實(shí)例的引用放在了一個(gè)類(lèi)的靜態(tài)域,比如Servlet框架中的HttpSession中。
    映射器實(shí)例
    映射器是一些由你創(chuàng)建的,綁定你映射的語(yǔ)句的接口,映射器接口的實(shí)例是從SqlSession中獲得的,因此從技術(shù)層面講,任何映射器實(shí)例的最大作用域是請(qǐng)求他們的的SqlSession相同的,盡管如此,映射器實(shí)例的最佳作用域是方法作用域。也就是說(shuō),映射器實(shí)例應(yīng)該在調(diào)用它們的方法中被請(qǐng)求,用過(guò)之后即可丟棄。并不需要顯示地關(guān)閉映射器實(shí)例。
    總的來(lái)說(shuō),MyBatis在易用性上要比JDBC好太多,不過(guò)JDBC與MyBatis的目標(biāo)不同,JDBC是作為一種基礎(chǔ)服務(wù),而MyBatis則是構(gòu)建在基礎(chǔ)服務(wù)之上的框架。所以JDBC的流程繁瑣,從JDBC的角度來(lái)說(shuō),這里的每一個(gè)步驟對(duì)于完成數(shù)據(jù)訪(fǎng)問(wèn)請(qǐng)求來(lái)說(shuō)都是必須的。

使用Spring JDBC訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)

Spring JDBC是在JDBC上面做的一層比較薄的封裝,主要是為了解決直接使用JDBC的一些痛點(diǎn),易用性得到了不少的提升。
引入的依賴(lài)

    <properties>
        <spring.version>4.3.17.RELEASE</spring.version>
    </properties>
 <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>

在使用Spring JDBC之前我們需要做一些配置,我們新建一個(gè)配置文件,命名為application.xml,在此配置文件中,我們配置了
數(shù)據(jù)庫(kù)的連接信息dataSource,注冊(cè)了JdbcTemplate實(shí)例。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">


    <context:property-placeholder  location="jdbc.properties"/>

    <bean id="dataSource" class="org.apache.ibatis.datasource.pooled.PooledDataSource">
        <!-- 配置與數(shù)據(jù)庫(kù)交互的4個(gè)必要屬性 -->
        <property name="driver" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>
</beans>

配置完成之后,我們可以寫(xiě)一個(gè)測(cè)試類(lèi)來(lái)測(cè)試一下。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:chapter1/application.xml")
public class SpringJdbcTest {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Test
    public void  testSpringJdbc() {
        String sql = "select id,name,age from student where name LIKE ?";
        List<Student> studentList = jdbcTemplate.query(sql, new Object[]{"%點(diǎn)點(diǎn)%"}, new BeanPropertyRowMapper<Student>(Student.class));
        System.out.println("----->執(zhí)行的sql={}"+sql);
        System.out.println("----->查詢(xún)結(jié)果={}"+studentList.get(0).toString());
    }
}

運(yùn)行結(jié)果
在這里插入圖片描述
從上面的測(cè)試代碼我們可以看出,相對(duì)于原生JDBC,Spring JDBC 易用性大大提升,注入jdbcTemplate之后,我們就可以通過(guò)jdbcTemplate來(lái)操作,只關(guān)注sql的執(zhí)行以及結(jié)果的處理即可。代碼簡(jiǎn)化了很多。但是SQL語(yǔ)句仍然寫(xiě)在代碼中。

使用Hibernate 訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)

本節(jié)會(huì)像之前的章節(jié)一樣,我會(huì)先寫(xiě)代碼進(jìn)行演示,然后在對(duì)比Hibernate 和MyBatis的區(qū)別。

Hibernate 訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)的過(guò)程演示

首先,在POM文件中添加所需依賴(lài)

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.3.2.Final</version>
        </dependency>

接著進(jìn)行環(huán)境配置,主要是關(guān)于數(shù)據(jù)庫(kù)方面的配置。

<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/mybatisdemo</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">admin</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
        <property name="hibernate.show_sql">true</property>
        <mapping resource="chapter1/xml/Student.hbm.xml" />
    </session-factory>
</hibernate-configuration>

環(huán)境配置完成之后,我們接著編寫(xiě)映射文件,將表字段與實(shí)體類(lèi)的屬性關(guān)聯(lián)起來(lái)。如下Student.hbm.xml

<hibernate-mapping package="com.jay.entity">
    <class table="student" name="Student">
        <id name="id" column="id">
            <generator class="native"/>
        </id>
        <property name="name" column="name"/>
        <property name="age" column="age"/>
        <property name="classId" column="class_id"/>
    </class>
</hibernate-mapping>

所有配置完成之后,我們就可以開(kāi)始編寫(xiě)測(cè)試代碼進(jìn)行測(cè)試:

public class HibernateTest {
    private SessionFactory sessionFactory;


    @Before
    public void init() {
        Configuration configuration = new Configuration();
        configuration.configure("chapter1/hibernate.cfg.xml");
        sessionFactory = configuration.buildSessionFactory();
    }

    @After
    public void destroy() {
        sessionFactory.close();
    }

    @Test
    public void testORM() {
        System.out.println("--------------ORM Query-------------");

        Session session = null;

        try {
            session = sessionFactory.openSession();
            int id = 1;
            Student student = session.get(Student.class, id);
            System.out.println("ORM Query Result:");
            System.out.println(student.toString());
            System.out.println();
        } finally {
            if (Objects.nonNull(session)) {
                session.close();
            }
        }
    }

    @Test
    public void testHQL() {
        System.out.println("--------------HQL Query-----------");
        Session session = null;

        try {
            session = sessionFactory.openSession();
            String hql = "FROM Student WHERE name=:name";
            Query query = session.createQuery(hql);
            query.setParameter("name", "點(diǎn)點(diǎn)");

            List<Student> studentList = query.list();
            System.out.println("HQL Query Result:");
            studentList.forEach(System.out::println);
            System.out.println();
        } finally {
            if (Objects.nonNull(session)) {
                session.close();
            }
        }
    }

   @Test
    public void testJpaCriteria() {
       System.out.println("-------------JPA Criteria-------------");

       Session session = null;

       try {
           session = sessionFactory.openSession();
           CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
           CriteriaQuery<Student> criteriaQuery = criteriaBuilder.createQuery(Student.class);
//       定義FROM子句
           Root<Student> student = criteriaQuery.from(Student.class);
//       構(gòu)建查詢(xún)條件
           Predicate equal = criteriaBuilder.equal(student.get("name"), "點(diǎn)點(diǎn)");
//       通過(guò)具有語(yǔ)義化的方法構(gòu)建SQL,等價(jià)于SELECT ... FROM student WHERE ...
           criteriaQuery.select(student).where(equal);

           Query<Student> query = session.createQuery(criteriaQuery);
           List<Student> studentList = query.getResultList();
           System.out.println("JPA Criteria Query Result:");
           studentList.forEach(System.out::println);
       } finally {
           if (Objects.nonNull(session)) {
               session.close();
           }
       }

   }
}

如上代碼清單所示,我編寫(xiě)了三個(gè)測(cè)試用例,第一個(gè)直接使用Hibernate生成SQL的功能,如果查詢(xún)比較簡(jiǎn)單可以采用此種方式,生成的SQL是

select student0_.id as id1_0_0_, student0_.name as name2_0_0_, student0_.age as age3_0_0_, student0_.class_id as class_id4_0_0_ from student student0_ where student0_.id=?

第二個(gè)測(cè)試用例,我編寫(xiě)了一條HQL語(yǔ)句,并通過(guò)Query來(lái)設(shè)置參數(shù),同樣Hibernate在運(yùn)行時(shí)會(huì)將HQL轉(zhuǎn)化成對(duì)應(yīng)的SQL,轉(zhuǎn)化后的SQL如下:

select student0_.id as id1_0_, student0_.name as name2_0_, student0_.age as age3_0_, student0_.class_id as class_id4_0_ from student student0_ where student0_.name=?

第三個(gè)測(cè)試用例,我們使用JPA Criteria 進(jìn)行查詢(xún),JPA Criteria 具有類(lèi)型安全,面向?qū)ο蠛驼Z(yǔ)義化的特點(diǎn),使用JPA Criteria,我們可以用寫(xiě)Java 代碼的方式進(jìn)行數(shù)據(jù)庫(kù)操作,無(wú)需手寫(xiě)SQL,第三個(gè)用例和第二個(gè)用例進(jìn)行的是同樣的查詢(xún),所以生成的SQL區(qū)別不大。
測(cè)試代碼的運(yùn)行結(jié)果:
在這里插入圖片描述

MyBatis VS Hibernate

至此,我們已經(jīng)對(duì)MyBatis和Hibernate訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)的過(guò)程都做了一次演示,下面我們來(lái)對(duì)比下MyBatis和Hibernate

  1. MyBatis 需要使用者自行維護(hù)SQL,靈活性高,方便對(duì)sql進(jìn)行優(yōu)化,Hibernate 可以自動(dòng)生成SQL,使用成本小。
  2. MyBatis 適合于需求變動(dòng)頻繁,業(yè)務(wù)量的系統(tǒng),Hibernate 更加適合于變動(dòng)比較小的系統(tǒng),比如OA系統(tǒng)

使用Spring Data JPA 訪(fǎng)問(wèn)數(shù)據(jù)庫(kù)

首先引入依賴(lài)

  <properties>
        <spring.version>4.3.17.RELEASE</spring.version>
    </properties>
 <!--///Spring JPA-->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>1.11.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.6.12</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.12</version>
        </dependency>

接著添加配置文件application-jpa.xml,主要是配置數(shù)據(jù)庫(kù)連接信息,以及事務(wù)相關(guān)的信息

<!--啟用注解配置和包掃描-->
    <context:annotation-config/>
    <context:component-scan base-package="com.jay"/>
    <!--創(chuàng)建Spring Data JPA實(shí)例對(duì)象-->
    <jpa:repositories base-package="com.jay.chapter1"/>

    <context:property-placeholder  location="jdbc.properties"/>

    <bean id="dataSource"
          class="org.apache.ibatis.datasource.pooled.PooledDataSource">
        <!-- 配置與數(shù)據(jù)庫(kù)交互的4個(gè)必要屬性 -->
        <property name="driver" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <bean id="entityManagerFactory"
          class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="packagesToScan" value="com.jay.entity"/>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="generateDdl" value="true"/>
                <property name="showSql" value="true"/>
            </bean>
        </property>
    </bean>
    <!--事務(wù)管理器-->
    <bean id="transactionManager"
          class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>
    <!--事務(wù)管理-->
    <tx:advice id="transactionAdvice"
               transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut id="daoPointCut" expression="execution(* com.jay.chapter1.mapper.*.*(..))"/>
        <aop:advisor advice-ref="transactionAdvice" pointcut-ref="daoPointCut"/>
    </aop:config>

配置文件添加完成之后,接著我們編寫(xiě)一個(gè)接口繼承CrudRepository接口,使其具備基本的增刪改查功能。

public interface JpaStudentDao extends CrudRepository<JpaStudent,Integer>{

    /**
     * @param name
     * @return
     */
    List<JpaStudent> getByNameLike(String name);

}

DAO接口添加完成之后,接著我們添加一個(gè)測(cè)試類(lèi)進(jìn)行測(cè)試。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:chapter1/application-jpa.xml")
public class JPATest {
    @Autowired
    JpaStudentDao jpaStudentDao;

    @Before
   public void init() {
        JpaStudent jpaStudent = new JpaStudent("張三", 12, "121");
        jpaStudentDao.save(jpaStudent);
    }

    @Test
    public void testCrudRepostitory() {
        List<JpaStudent> jpaStudents = jpaStudentDao.getByNameLike("張三");
        jpaStudents.forEach(System.out::println);
        System.out.println();
    }
}

如上測(cè)試類(lèi)所示,我先使用了JPA自帶的save方法向數(shù)據(jù)庫(kù)中插入了一條數(shù)據(jù),接著自定義了一個(gè)查詢(xún)方法。JPA中查詢(xún)方法可以由我們聲明的命名查詢(xún)生成,也可以由方法名解析
方法名以find…By, read…By, query…By, count…By和 get…By做開(kāi)頭。在By之前可以添加Distinct表示查找不重復(fù)數(shù)據(jù)。By之后是真正的查詢(xún)條件。
可以查詢(xún)某個(gè)屬性,也可以使用條件進(jìn)行比較復(fù)雜的查詢(xún),例如Between, LessThan, GreaterThan, Like,And,Or等。
字符串屬性后面可以跟IgnoreCase表示不區(qū)分大小寫(xiě),也可以后跟AllIgnoreCase表示所有屬性都不區(qū)分大小寫(xiě)。
可以使用OrderBy對(duì)結(jié)果進(jìn)行升序或降序排序。
可以查詢(xún)屬性的屬性,直接將幾個(gè)屬性連著寫(xiě)即可,如果可能出現(xiàn)歧義屬性,可以使用下劃線(xiàn)分隔多個(gè)屬性。
運(yùn)行結(jié)果如下:
在這里插入圖片描述

MyBatis VS JPA

通過(guò)上面的實(shí)例,我們可以了解到JPA的使用,JPA類(lèi)似于Hibernate都可以自動(dòng)生成SQL,不同之處是,JPA還可以根據(jù)方法名來(lái)解析生成sql。MyBatis 還是需要使用者自行維護(hù)sql。

總結(jié)

本篇文章對(duì)MyBatis 是什么,為什么使用,以及與其他ORM框架進(jìn)行了對(duì)比。

參考文獻(xiàn)

MyBatis官方文檔
MyBatis 源碼分析系列文章導(dǎo)讀
《MyBatis 技術(shù)內(nèi)幕》- 徐郡明
Spring Data JPA 介紹和使用

源代碼

https://github.com/XWxiaowei/MyBatisLearn/tree/master/mybatisDemo




作者:碼農(nóng)飛哥
微信公眾號(hào):碼農(nóng)飛哥