最初設計時,MyBatis 是一個 XML 驅動的框架。配置信息是基於 XML 的,並且映射語句也是定義在 XML 中的。隨着技術的更新發展,對於開發效率要求也原來越高,特別是一些小型項目;愈來愈多的框架開始支持註解,java
到MyBatis3時,MyBatis對註解有了完善的支持,利用註解能夠在一些狀況下提升開發效率sql
但不幸的是,Java 註解的的表達力和靈活性十分有限。儘管不少時間都花在調查、設計和試驗上, 最強大的 MyBatis 映射並不能用註解來構建數據庫
接口方法聲明:apache
import com.yyh.pojo.User; import org.apache.ibatis.annotations.Select; public interface UserMapper2 { @Select("select * from kuser where id = #{id}") public User selectUserByID(int id); }
測試方法:跨域
@Test public void selectTest(){ SqlSession session = factory.openSession(); UserMapper2 mapper = session.getMapper(UserMapper2.class); User user = mapper.selectUserByID(2); System.out.println(user); session.close(); }
不要忘記註冊這個接口到全局配置中session
<mappers> <mapper class="com.yyh.mapper.UserMapper2"/> </mappers>
接口方法聲明:mybatis
@Select("select * from kuser where sex = #{sex} and name like '%${name}%'") public List<User> selectUserBySexAndName(@Param("sex") String sex, @Param("name") String name);
測試方法:app
@Test public void selectTest2(){ SqlSession session = factory.openSession(); UserMapper2 mapper = session.getMapper(UserMapper2.class); List<User> users = mapper.selectUserBySexAndName("1","張"); System.out.println(users); session.close(); }
必定要記住MyBatis的sql接受的參數只有一個不管實際傳了幾個框架
當sql語句須要多個參數時則必須將多個參數打包到一個對象中,一般是POJO或Map,上面的案例中使用了@Param註解本質就是告訴MyBatis有多個參數MyBatis會自動建立一個Map,而後將@Param的值做爲Key,而後將Map傳給sql,因此你也能夠手動傳一個Mapmaven
接口方法聲明:
@Select("select * from kuser where sex = #{sex} and name like '%${name}%'") public List<User> selectUserBySexAndName(Map<String,Object> params);
測試方法:
@Test public void selectTest2(){ SqlSession session = factory.openSession(); UserMapper2 mapper = session.getMapper(UserMapper2.class); Map<String,Object> params = new HashMap<>(); //存儲參數的Map params.put("sex","1"); params.put("name","張"); List<User> users = mapper.selectUserBySexAndName(params); System.out.println(users); session.close(); }
接口方法聲明:
@Insert("insert into kuser values(null,#{name},#{birthday},#{sex},#{address})") public int insertUser(User user);
測試方法:
@Test public void insertTest() { SqlSession session = factory.openSession(); UserMapper2 mapper = session.getMapper(UserMapper2.class); User user = new User(); user.setName("jerry"); user.setSex("1"); user.setAddress("亞洲中國"); user.setBirthday(new Date()); mapper.insertUser(user); session.commit(); session.close(); }
在@select註解的下方添加@selectKey註解來完成對自增主鍵的獲取
@Insert("insert into kuser values(null,#{name},#{birthday},#{sex},#{address})") @SelectKey(statement = "select last_insert_id()",keyProperty = "id",resultType = Integer.class,before = false) public int insertUser(User user);
在執行insert以後執行last_insert_id()函數獲取自增值,而後放入對象的某個屬性中;
接口方法聲明:
@Update("update kuser set name = #{name}, birthday = #{birthday}, sex = #{sex}, address = #{address} where id = #{id}") public int updateUser(User u); // 若是一行太長能夠換行些 可是要注意sql語法
測試方法:
@Test public void updateTest() { SqlSession session = factory.openSession(); UserMapper2 mapper = session.getMapper(UserMapper2.class); User user = mapper.selectUserByID(1); user.setName("王六子"); mapper.updateUser(user); session.commit(); session.close(); }
接口方法聲明:
@Delete("delete from kuser where id = #{id}") public int deleteUserByID(int id);
測試方法:
@Test public void deleteTest() { SqlSession session = factory.openSession(); UserMapper2 mapper = session.getMapper(UserMapper2.class); mapper.deleteUserByID(12); session.commit(); session.close(); }
動態sql指語句中包含邏輯代碼,須要先運行邏輯代碼,最後產生sql語句,因此須要在註解中告訴MyBatis這是一個動態sql,經過<script>sql....</script>
語法來指定;
若想要在sql中使用各類標籤則必須添加上述根標籤,不然MyBatis會將總體做爲sql語句
接口方法聲明:
@Select("<script>" + "select * from kuser" + "<where>" + "<if test='name != null'>" + "and name like '%${name}%'" + "</if>" + "<if test='sex != null'>" + "and sex = #{sex}" + "</if>" + "</where>" + "</script>") public List<User> searchUserByNameAndSex(@Param("name") String name,@Param("sex") String sex);
測試代碼:
@Test public void dynamicSqlTest(){ SqlSession session = factory.openSession(); UserMapper2 mapper = session.getMapper(UserMapper2.class); List<User> users = mapper.searchUserByNameAndSex(null,null); // List<User> users = mapper.searchUserByNameAndSex("張",null); // List<User> users = mapper.searchUserByNameAndSex("張", "2"); System.out.println(users); session.close(); }
準備工做:將數據庫中的name字段修改成username,而後咱們經過ResultMap來手動映射name字段
接口方法聲明:
@Select("select *from kuser where username = #{name}") @Results({ @Result(id = true,column = "id",property = "id"), @Result(column = "username",property = "name"), }) public User selectUserByName(String name);
測試代碼省略..
能夠發現,MyBatis默認會自動映射全部字段和屬性匹配的數據,另外id表示是否爲主鍵字段,默認爲false
強調:Results能夠位於對應方法的上面或下面,可是沒法跨域其餘方法,默認只對當前方法有效,若是須要重複使用則須要爲其指定id
接口方法聲明:
//定義 @Results(id="map1",value = { @Result(id = true,column = "id",property = "id"), @Result(column = "username",property = "name"), }) //.....中間必須間隔其餘方法不能當即應用到某個ResultMap
使用:
@Select("select *from kuser where username = #{name}") //經過@ResultMap註解 並傳入id來使用 @ResultMap("map1") public User selectUserByName(String name);
注意:@Results的定義不能不能和使用它的@ResultMap一塊兒出現,既然是重複使用的,那我建議統必定義在接口的最上面
一對多關聯
//實現根據用戶姓名查詢用戶信息和訂單信息 @Select("select *from kuser where username = #{name}") @Results(value = { @Result(id = true,column = "id",property = "id"), @Result(column = "username",property = "name"), //一對多關聯,指定子查詢語句的方法名稱(全限定名稱)column指定傳給子查詢的參數 @Result(column = "id",property = "orders",many = @Many(select = "com.yyh.mapper.UserMapper2.selectOrdersByID")), }) public User selectUserAdnOrdersByUserName(String name); //注意這裏的條件字段時order表中的字段 @Select("select *from Orders where user_id = #{id}") public List<Order> selectOrdersByID(int id);
一對一關聯 只須要修改屬性名稱和註解名稱便可:
@Select("select *from orders where id = #{id}") @Results(value = { @Result(id = true,column = "id",property = "id"), @Result(column = "user_id",property = "user" ,one = @One(select = "com.yyh.mapper.UserMapper2.selectUserByID")), }) public Order selectOrderByID(int id);
generator翻譯爲生成器,是MyBatis開源的一個插件,能夠從數據庫獲取表信息,自動生成Mapper.xml
,POJO
,以及Mapper
接口
但問題是,MyBatis不可能徹底清楚咱們的業務需求,因此其自動生成的sql只能知足基本的CRUD操做,而沒法幫助咱們進行連表操做,(固然包括帶有條件的CRUD)
<build> <plugins> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.7</version> <configuration> <!-- 是否覆蓋已存在的接口和POJO--> <overwrite>true</overwrite> </configuration> </plugin> </plugins> </build>
generatorConfig.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <!--導入屬性配置--> <properties resource="jdbc.properties"></properties> <!--指定特定數據庫的jdbc驅動jar包的位置--> <classPathEntry location="${location}"/> <context id="default" targetRuntime="MyBatis3"> <!-- optional,旨在建立class時,對註釋進行控制 --> <commentGenerator> <property name="suppressDate" value="true"/> <property name="suppressAllComments" value="true"/> </commentGenerator> <!--jdbc的數據庫鏈接 --> <jdbcConnection driverClass="${driver}" connectionURL="${url}" userId="${user}" password="${password}"> </jdbcConnection> <!-- 非必需,類型處理器,在數據庫類型和java類型之間的轉換控制--> <javaTypeResolver> <property name="forceBigDecimals" value="false"/> </javaTypeResolver> <!--Model模型生成器,用來生成含有主鍵key的類,記錄類 以及查詢Example類 targetPackage 指定生成的model生成所在的包名 targetProject 指定在該項目下所在的路徑 --> <javaModelGenerator targetPackage="com.yyh.pojo" targetProject="src/main/java"> <!-- 是否容許子包,即targetPackage.schemaName.tableName --> <property name="enableSubPackages" value="false"/> <!-- 是否對model添加 構造函數 --> <property name="constructorBased" value="true"/> <!-- 是否對類CHAR類型的列的數據進行trim操做 --> <property name="trimStrings" value="true"/> <!-- 創建的Model對象是否 不可改變 即生成的Model對象不會有 setter方法,只有構造方法 --> <property name="immutable" value="false"/> </javaModelGenerator> <!--mapper映射文件生成所在的目錄 爲每個數據庫的表生成對應的SqlMap文件 --> <sqlMapGenerator targetPackage="com.yyh.dao" targetProject="src/main/resources"> <property name="enableSubPackages" value="false"/> </sqlMapGenerator> <!--mapper接口文件生成所在的目錄 爲每個數據庫的表生成對應的接口文件 --> <javaClientGenerator type="XMLMAPPER" targetPackage="com.yyh.dao" targetProject="src/main/java"> <!-- enableSubPackages:是否讓schema(數據庫名稱)做爲包的後綴 --> <property name="enableSubPackages" value="false"/> </javaClientGenerator> <!--指定須要生成的表--> <table tableName="category"></table> <table tableName="orders"></table> <table tableName="products"></table> <table tableName="kuser"></table> </context> </generatorConfiguration>
上述配置是一個較爲通用的配置,實際開發中要根據需求進行修改
若自定義配置文件名稱則須要在pom中指定
<build> <plugins> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.7</version> <configuration> <!-- 自定義配置文件 相對於項目根目錄--> <configurationFile>src/main/resources/aaaa.xml</configurationFile> <overwrite>true</overwrite> </configuration> </plugin> </plugins> </build>
可在idea右側的maven菜單中雙擊執行mybatis-generator:generate
也可利用maven命令執行:mybatis-generator:generate
generator的目標是儘量的幫咱們減小sql的編寫,若是隻能進行簡單的CRUD那意義不大,因而generator使用了一套Example來幫助咱們用OOP(面向對象)的方式來完成SQL中的條件拼接
其設計思想是將條件看作是一個對象,該對象包含了SQL中常見的比較,邏輯運算等......打開文件你會發現其本質就是幫咱們拼接響應的sql符號和關鍵字
import com.yyh.dao.KuserMapper; import com.yyh.pojo.Kuser; import com.yyh.pojo.KuserExample; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.util.List; public class GeneratorTest { private SqlSessionFactory factory; @Before public void init() throws IOException { //獲取的工廠構造器 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //加載配置文件 InputStream stream = Resources.getResourceAsStream("mybatis-config.xml"); //得到會話工廠 factory = builder.build(stream); } //查詢 @Test public void test(){ SqlSession session = factory.openSession(); KuserMapper mapper = session.getMapper(KuserMapper.class); Kuser kuser = mapper.selectByPrimaryKey(1); System.out.println(kuser.getSex()); System.out.println(kuser.getAddress()); System.out.println(kuser.getBirthday()); System.out.println(kuser.getUsername()); } //修改 @Test public void test2(){ SqlSession session = factory.openSession(); KuserMapper mapper = session.getMapper(KuserMapper.class); Kuser kuser = mapper.selectByPrimaryKey(1); kuser.setUsername("XXXXXXXXX"); mapper.updateByPrimaryKey(kuser); session.commit(); } //添加 @Test public void test3(){ SqlSession session = factory.openSession(); KuserMapper mapper = session.getMapper(KuserMapper.class); Kuser auser = new Kuser(); auser.setUsername("jack"); auser.setAddress("北京東城"); mapper.insert(auser); session.commit(); } //刪除 @Test public void test4() { SqlSession session = factory.openSession(); KuserMapper mapper = session.getMapper(KuserMapper.class); mapper.deleteByPrimaryKey(13); session.commit(); } //and條件 @Test public void test5() { SqlSession session = factory.openSession(); KuserMapper mapper = session.getMapper(KuserMapper.class); KuserExample kuserExample = new KuserExample(); KuserExample.Criteria criteria = kuserExample.createCriteria(); criteria.andBirthdayIsNotNull(); criteria.andUsernameLike("%張%"); List<Kuser> kusers = mapper.selectByExample(kuserExample); System.out.println(kusers); } // or條件 @Test public void test6() { SqlSession session = factory.openSession(); KuserMapper mapper = session.getMapper(KuserMapper.class); KuserExample kuserExample = new KuserExample(); //建立一個條件對象,能夠包含n個and KuserExample.Criteria criteria1 = kuserExample.createCriteria(); criteria1.andUsernameLike("%張%"); //建立一個條件對象能夠包含n個and,且前面添加or關鍵字 KuserExample.Criteria criteria2 = kuserExample.or(); criteria2.andBirthdayIsNull(); //最終的意思是 名字帶有張的 或者生日爲空的; 具體邏輯可根據生產的sql進行分析 List<Kuser> kusers = mapper.selectByExample(kuserExample); System.out.println(kusers); } }