orm框架的本質是簡化編程中操做數據庫的編碼,發展到如今基本上就剩兩家了,一個是宣稱能夠不用寫一句SQL的hibernate,一個是能夠靈活調試動態sql的mybatis,二者各有特色,在企業級系統開發中能夠根據需求靈活使用。發現一個有趣的現象:傳統企業大都喜歡使用hibernate,互聯網行業一般使用mybatis。java
hibernate特色就是全部的sql都用Java代碼來生成,不用跳出程序去寫(看)sql,有着編程的完整性,發展到最頂端就是spring data jpa這種模式了,基本上根據方法名就能夠生成對應的sql了。mysql
mybatis初期使用比較麻煩,須要各類配置文件、實體類、dao層映射關聯、還有一大推其它配置。固然mybatis也發現了這種弊端,初期開發了generator能夠根據表結果自動生產實體類、配置文件和dao層代碼,能夠減輕一部分開發量;後期也進行了大量的優化可使用註解了,自動管理dao層和配置文件等,發展到最頂端就是springboot+mybatis能夠徹底註解,不用配置文件,也能夠簡單配置輕鬆上手。git
官方說明:MyBatis Spring-Boot-Starter will help you use MyBatis with Spring Boot
其實就是MyBatis爲了配合使用spring boot開發出的一套解決方案。mybatis-spring-boot-starter主要有兩種解決方案,一種是使用註解,一種是簡化後的傳統方式。github
固然任何模式都須要首先引入mybatis-spring-boot-starter的pom文件web
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.1.1</version> </dependency>
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> </dependencies>
application.properties
添加相關配置mybatis.type-aliases-package=com.neo.entity spring.datasource.driverClassName = com.mysql.jdbc.Driver spring.datasource.url = jdbc:mysql://localhost:3306/dataBaseName?useUnicode=true&characterEncoding=utf-8 spring.datasource.username = username spring.datasource.password = password
springboot會自動加載spring.datasource.*相關配置,數據源就會自動注入到sqlSessionFactory中,sqlSessionFactory會自動注入到Mapper中。spring
在啓動類中添加對mapper包掃描@MapperScan
sql
@SpringBootApplication @MapperScan("com.neo.mapper") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
或者直接在Mapper類上面添加註解@Mapper
,建議使用上面那種,不然每一個mapper加個註解比較麻煩。數據庫
public interface UserMapper { @Select("SELECT * FROM users") @Results({ @Result(property = "userSex", column = "user_sex", javaType = UserSexEnum.class), @Result(property = "nickName", column = "nick_name") }) List<UserEntity> getAll(); @Select("SELECT * FROM users WHERE id = #{id}") @Results({ @Result(property = "userSex", column = "user_sex", javaType = UserSexEnum.class), @Result(property = "nickName", column = "nick_name") }) UserEntity getOne(Long id); @Insert("INSERT INTO users(userName,passWord,user_sex) VALUES(#{userName}, #{passWord}, #{userSex})") void insert(UserEntity user); @Update("UPDATE users SET userName=#{userName},nick_name=#{nickName} WHERE id =#{id}") void update(UserEntity user); @Delete("DELETE FROM users WHERE id =#{id}") void delete(Long id); }
註解以下表所示: 編程
註解 | 使用對象 | 相對應的 XML | 描述 |
---|---|---|---|
@CacheNamespace | 類 | <cache> | 爲給定的命名空間(好比類)配置緩存。屬性有:implemetation, eviction, flushInterval, size, readWrite, blocking 和properties。 |
@Property | N/A | <property> | 指定參數值或佔位值(placeholder)(能被 mybatis-config.xml內的配置屬性覆蓋)。屬性有:name, value。(僅在MyBatis 3.4.2以上版本生效) |
@CacheNamespaceRef | 類 | <cacheRef> | 參照另一個命名空間的緩存來使用。屬性有:value, name。若是你使用了這個註解,你應設置 value 或者 name 屬性的其中一個。value 屬性用於指定 Java 類型而指定命名空間(命名空間名就是指定的 Java 類型的全限定名),name 屬性(這個屬性僅在MyBatis 3.4.2以上版本生效)直接指定了命名空間的名字。 |
@ConstructorArgs | 方法 | <constructor> | 收集一組結果傳遞給一個結果對象的構造方法。屬性有:value,它是形式參數數組。 |
@Arg | N/A |
|
單參數構造方法,是 ConstructorArgs 集合的一部分。屬性有:id, column, javaType, jdbcType, typeHandler, select 和 resultMap。id 屬性是布爾值,來標識用於比較的屬性,和<idArg> XML 元素類似。 |
@TypeDiscriminator | 方法 | <discriminator> | 一組實例值被用來決定結果映射的表現。屬性有:column, javaType, jdbcType, typeHandler 和 cases。cases 屬性是實例數組。 |
@Case | N/A | <case> | 單獨實例的值和它對應的映射。屬性有:value, type, results。results 屬性是結果數組,所以這個註解和實際的 ResultMap 很類似,由下面的 Results 註解指定。 |
@Results | 方法 | <resultMap> | 結果映射的列表,包含了一個特別結果列如何被映射到屬性或字段的詳情。屬性有:value, id。value 屬性是 Result 註解的數組。這個 id 的屬性是結果映射的名稱。 |
@Result | N/A |
|
在列和屬性或字段之間的單獨結果映射。屬性有:id, column, javaType, jdbcType, typeHandler, one, many。id 屬性是一個布爾值,來標識應該被用於比較(和在 XML 映射中的<id>類似)的屬性。one 屬性是單獨的聯繫,和 <association> 類似,而 many 屬性是對集合而言的,和<collection>類似。它們這樣命名是爲了不名稱衝突。 |
@One | N/A | <association> | 複雜類型的單獨屬性值映射。屬性有:select,已映射語句(也就是映射器方法)的全限定名,它能夠加載合適類型的實例。fetchType會覆蓋全局的配置參數 lazyLoadingEnabled。注意聯合映射在註解 API中是不支持的。這是由於 Java 註解的限制,不容許循環引用。 |
@Many | N/A | <collection> | 映射到複雜類型的集合屬性。屬性有:select,已映射語句(也就是映射器方法)的全限定名,它能夠加載合適類型的實例的集合,fetchType 會覆蓋全局的配置參數 lazyLoadingEnabled。注意 聯合映射在註解 API中是不支持的。這是由於 Java 註解的限制,不容許循環引用 |
@MapKey | 方法 | 這是一個用在返回值爲 Map 的方法上的註解。它可以將存放對象的 List 轉化爲 key 值爲對象的某一屬性的 Map。屬性有: value,填入的是對象的屬性名,做爲 Map 的 key 值。 | |
@Options | 方法 | 映射語句的屬性 | 這個註解提供訪問大範圍的交換和配置選項的入口,它們一般在映射語句上做爲屬性出現。Options 註解提供了通俗易懂的方式來訪問它們,而不是讓每條語句註解變複雜。屬性有:useCache=true, flushCache=FlushCachePolicy.DEFAULT, resultSetType=FORWARD_ONLY, statementType=PREPARED, fetchSize=-1, timeout=-1, useGeneratedKeys=false, keyProperty="id", keyColumn="", resultSets=""。值得一提的是, Java 註解沒法指定 null 值。所以,一旦你使用了 Options 註解,你的語句就會被上述屬性的默認值所影響。要注意避免默認值帶來的預期之外的行爲。 注意: keyColumn 屬性只在某些數據庫中有效(如 Oracle、PostgreSQL等)。請在插入語句一節查看更多關於 keyColumn 和 keyProperty 二者的有效值詳情。 |
|
方法 |
|
這四個註解分別表明將會被執行的 SQL 語句。它們用字符串數組(或單個字符串)做爲參數。若是傳遞的是字符串數組,字符串之間先會被填充一個空格再鏈接成單個完整的字符串。這有效避免了以 Java 代碼構建 SQL 語句時的「丟失空格」的問題。然而,你也能夠提早手動鏈接好字符串。屬性有:value,填入的值是用來組成單個 SQL 語句的字符串數組。 |
|
方法 |
|
容許構建動態 SQL。這些備選的 SQL 註解容許你指定類名和返回在運行時執行的 SQL 語句的方法。(自從MyBatis 3.4.6開始,你能夠用 CharSequence 代替 String 來返回類型返回值了。)當執行映射語句的時候,MyBatis 會實例化類並執行方法,類和方法就是填入了註解的值。你能夠把已經傳遞給映射方法了的對象做爲參數,"Mapper interface type" 和 "Mapper method" 會通過 ProviderContext (僅在MyBatis 3.4.5及以上支持)做爲參數值。(MyBatis 3.4及以上的版本,支持多參數傳入)屬性有: type, method。type 屬性需填入類。method 需填入該類定義了的方法名。注意 接下來的小節將會討論類,能幫助你更輕鬆地構建動態 SQL。 |
@Param | 參數 | N/A | 若是你的映射方法的形參有多個,這個註解使用在映射方法的參數上就能爲它們取自定義名字。若不給出自定義名字,多參數(不包括 RowBounds 參數)則先以 "param" 做前綴,再加上它們的參數位置做爲參數別名。例如 #{param1}, #{param2},這個是默認值。若是註解是 @Param("person"),那麼參數就會被命名爲 #{person}。 |
@SelectKey | 方法 | <selectKey> | 這個註解的功能與 <selectKey> 標籤徹底一致,用在已經被 @Insert 或 @InsertProvider 或 @Update 或 @UpdateProvider 註解了的方法上。若在未被上述四個註解的方法上做 @SelectKey 註解則視爲無效。若是你指定了 @SelectKey 註解,那麼 MyBatis 就會忽略掉由 @Options 註解所設置的生成主鍵或設置(configuration)屬性。屬性有:statement 填入將會被執行的 SQL 字符串數組,keyProperty 填入將會被更新的參數對象的屬性的值,before 填入 true 或 false 以指明 SQL 語句應被在插入語句的以前仍是以後執行。resultType 填入 keyProperty 的 Java 類型和用 Statement、 PreparedStatement 和 CallableStatement 中的 STATEMENT、 PREPARED 或 CALLABLE 中任一值填入 statementType。默認值是 PREPARED。 |
@ResultMap | 方法 | N/A | 這個註解給 @Select 或者 @SelectProvider 提供在 XML 映射中的 <resultMap> 的id。這使得註解的 select 能夠複用那些定義在 XML 中的 ResultMap。若是同一 select 註解中還存在 @Results 或者 @ConstructorArgs,那麼這兩個註解將被此註解覆蓋。 |
@ResultType | 方法 | N/A | 此註解在使用告終果處理器的狀況下使用。在這種狀況下,返回類型爲 void,因此 Mybatis 必須有一種方式決定對象的類型,用於構造每行數據。若是有 XML 的結果映射,請使用 @ResultMap註解。若是結果類型在 XML 的 <select> 節點中指定了,就不須要其餘的註解了。其餘狀況下則使用此註解。好比,若是 @Select 註解在一個將使用結果處理器的方法上,那麼返回類型必須是 void 而且這個註解(或者@ResultMap)必選。這個註解僅在方法返回類型是 void 的狀況下生效。 |
@Flush | 方法 | N/A |
注意,使用#符號和$符號的不一樣:數組
// This example creates a prepared statement, something like select * from teacher where name = ?; @Select("Select * from teacher where name = #{name}") Teacher selectTeachForGivenName(@Param("name") String name); // This example creates n inlined statement, something like select * from teacher where name = 'someName'; @Select("Select * from teacher where name = '${name}'") Teacher selectTeachForGivenName(@Param("name") String name);
@RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest { @Autowired private UserMapper UserMapper; @Test public void testInsert() throws Exception { UserMapper.insert(new UserEntity("aa", "a123456", UserSexEnum.MAN)); UserMapper.insert(new UserEntity("bb", "b123456", UserSexEnum.WOMAN)); UserMapper.insert(new UserEntity("cc", "b123456", UserSexEnum.WOMAN)); Assert.assertEquals(3, UserMapper.getAll().size()); } @Test public void testQuery() throws Exception { List<UserEntity> users = UserMapper.getAll(); System.out.println(users.toString()); } @Test public void testUpdate() throws Exception { UserEntity user = UserMapper.getOne(3l); System.out.println(user.toString()); user.setNickName("neo"); UserMapper.update(user); Assert.assertTrue(("neo".equals(UserMapper.getOne(3l).getNickName()))); } }
極簡xml版本保持映射文件的老傳統,優化主要體如今不須要實現dao的是實現層,系統會自動根據方法名在映射文件中找對應的sql.
pom文件和上個版本同樣,只是application.properties
新增如下配置
mybatis.config-locations=classpath:mybatis/mybatis-config.xml mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
指定了mybatis基礎配置文件和實體類映射文件的地址
mybatis-config.xml 配置
<configuration> <typeAliases> <typeAlias alias="Integer" type="java.lang.Integer" /> <typeAlias alias="Long" type="java.lang.Long" /> <typeAlias alias="HashMap" type="java.util.HashMap" /> <typeAlias alias="LinkedHashMap" type="java.util.LinkedHashMap" /> <typeAlias alias="ArrayList" type="java.util.ArrayList" /> <typeAlias alias="LinkedList" type="java.util.LinkedList" /> </typeAliases> </configuration>
這裏能夠添加一些mybatis基礎的配置
<mapper namespace="com.neo.mapper.UserMapper" > <resultMap id="BaseResultMap" type="com.neo.entity.UserEntity" > <id column="id" property="id" jdbcType="BIGINT" /> <result column="userName" property="userName" jdbcType="VARCHAR" /> <result column="passWord" property="passWord" jdbcType="VARCHAR" /> <result column="user_sex" property="userSex" javaType="com.neo.enums.UserSexEnum"/> <result column="nick_name" property="nickName" jdbcType="VARCHAR" /> </resultMap> <sql id="Base_Column_List" > id, userName, passWord, user_sex, nick_name </sql> <select id="getAll" resultMap="BaseResultMap" > SELECT <include refid="Base_Column_List" /> FROM users </select> <select id="getOne" parameterType="java.lang.Long" resultMap="BaseResultMap" > SELECT <include refid="Base_Column_List" /> FROM users WHERE id = #{id} </select> <insert id="insert" parameterType="com.neo.entity.UserEntity" > INSERT INTO users (userName,passWord,user_sex) VALUES (#{userName}, #{passWord}, #{userSex}) </insert> <update id="update" parameterType="com.neo.entity.UserEntity" > UPDATE users SET <if test="userName != null">userName = #{userName},</if> <if test="passWord != null">passWord = #{passWord},</if> nick_name = #{nickName} WHERE id = #{id} </update> <delete id="delete" parameterType="java.lang.Long" > DELETE FROM users WHERE id =#{id} </delete> </mapper>
public interface UserMapper { List<UserEntity> getAll(); UserEntity getOne(Long id); void insert(UserEntity user); void update(UserEntity user); void delete(Long id); }
對比上一步這裏所有隻剩了接口方法
使用和註解版本沒有區別。
兩種模式各有特色,註解版適合簡單快速的模式,相似微服務那種一個服務對應一個數據庫。
老傳統模式比適合大型項目,能夠靈活的動態生成SQL,方便修改SQL。