我們今天先來簡單了解一下我們持久層框架,mybatis的使用。而且現在的注解成為趨勢,我主要說一下注解方向的使用吧(配置文件也會說)
從使用角度只要是三個部分,mybatis-config.xml,mapper.xml,執行文件三個部分。
mybatis-config.xml:
主鍵標簽為configuration成對出現的,然后是properties也就是我們的配置,用於配置數據庫。settings聲明一些配置,比如打印sql語句等,后面會一個個去說。然后就是我們的mappers,里面包含多個mapper標簽,也就是對應我們的mapper.xml文件,在這里說一下一共有三種注入的方式,resource,class,url,resource是通過classpath配置的,如果你沒有把mapper放置在resources配置下面,需要在maven里設置編譯,不然我們的mapper.xml不會編譯到classpath里,class通過類來注入mapper,url一般是遠程注入的。再就是我們的typehandlers,可以指定類型轉換的。我們也可以繼承BaseTypeHandler來重寫父類的方法來自定義類型轉換。
來一個我自己的簡單配置。
<?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> <properties resource="app.properties"> <property name="jdbc.driver" value="com.mysql.jdbc.Driver"/> </properties> <settings> <!-- 打印查詢語句 --> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> <environments default="${default.environment}"> <environment id="dev"> <transactionManager type="JDBC"/> <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> </environment> </environments> <mappers> <mapper resource="mybatis/dao/StudentMapper.xml"/> <!-- <mapper class="com.tuling.mybatis.dao.UserMapper"></mapper>--> <!-- <mapper url="mybatis.dao.StudentDao"></mapper>--> </mappers> </configuration>
配置還要很多,后面源碼解析里面會一點點來說明。
mapper.xml:
這個文件就是我們的編寫sql的文件了,里面主要標簽就是select,insert,update,delete我們的增刪改查標簽,再就是我們的緩存設置(二級緩存)。下次博客主要說博客,源碼級的。
select里包含我們常見的id,resultType,resultMap,id用來指向我們的接口文件的類名,resultType為我們mybatis自帶的類型,也可以是我們設置的對象Bean,resultMap是我們自己定義的返回類型。這里可能會有疑問,一堆多應該怎么來配置?
association我們可以用他來指定一對多的配置,同時可以配置懶查詢還是及時查詢的。我們來看一個實例,我們現有學生表格分數表,學生對應很多科目的分數,我們來看一下。先來一段測試代碼。
<?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> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost/jdbc"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> <mappers> <!-- <mapper resource="mybatis/dao/StudentMapper.xml"/>--> <mapper class="mybatis.dao.StudentMapper"></mapper> <mapper class="mybatis.dao.ScoreMapper"></mapper> </mappers> </configuration>
<?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"> <mapper namespace="mybatis.dao.StudentMapper"> <select id="selectUser" resultType="mybatis.bean.StudentBean"> select * from stu where id = #{id} </select> </mapper>
package mybatis.bean; import java.io.Serializable; public class StudentBean implements Serializable { private static final long serialVersionUID = 2193971369901198487L; private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } @Override public String toString() { return "selectUser{" + "id=" + id + "name=" + name + '}'; } }
package mybatis; import mybatis.bean.ScoreBean; import mybatis.bean.StudentBean; import mybatis.dao.ScoreMapper; import mybatis.dao.StudentMapper; 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.Test; import java.io.IOException; import java.io.InputStream; import java.util.List; public class Test1 { @Test public void test() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession session = sqlSessionFactory.openSession(); StudentMapper mapper = session.getMapper(StudentMapper.class); StudentBean result = mapper.selectUser(1); System.out.println(result); } }
這樣我們查詢到我們的學生信息,但是還未包含我們的分數。我們來改造一下。
<?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"> <mapper namespace="mybatis.dao.StudentMapper"> <resultMap id="studentMap" type="mybatis.bean.StudentBean"> <id property="id" column="id"></id> <collection property="scoreBean" ofType="mybatis.bean.ScoreBean"> <id property="id" column="sid"></id> <!-- <result property="subject" column="subject"></result>--> <result property="score" column="score"></result> <result property="studentId" column="studentId"></result> </collection> </resultMap> <select id="selectUser" resultMap="studentMap"> select t.id,t.name,t.address,t.num,s.id as sid,s.subject,s.score,s.studentId as studentId from student t left join score s on s.studentId = t.id where t.id = #{id} </select> </mapper>
這樣就可以查詢到對應關系了。需要注意的事子表如果和主表重名,一定給子表起一個別名,而且子表的每一項需要寫result,不然沒有結果的,但是還不是很好,本來是一個對象一個集合,現在直接變成集合了,我們再來改改。
<?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"> <mapper namespace="mybatis.dao.StudentMapper"> <resultMap id="studentMap" type="mybatis.bean.StudentBean"> <id property="id" column="id"></id> <collection property="scoreBean" javaType="java.util.ArrayList" ofType="mybatis.bean.ScoreBean" select="mybatis.dao.ScoreMapper.selectScoreByStudentId" column="{studentId=id}"> </collection> </resultMap> <select id="selectUser" resultMap="studentMap"> select * from student t where t.id = #{id} </select> </mapper>
這個比較好用,但是切記,不是懶加載,不是懶加載,需要注意的是collection的property指定我們實體類Bean類中集合的名字。ofType是指向我們一對多中多方的實體Bean,select指定我們對應的第二句sql語句,也就是我們的子查詢語句。
column="{studentId=id}" 中studentId是我們的子查詢參數名,id是和我們主表的對應關系。就是說,我們要子表的什么參數等於我們的主表的哪個參數傳遞過去。
接下來就是我們簡單的一對一了(也可以當做一對多,但是沒啥卵用的多對一,項目經理讓從多往一查的時候,請你吐他。。。)我們來看我一下我的配置
<?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"> <mapper namespace="mybatis.dao.ScoreMapper"> <resultMap id="scoreMap" type="mybatis.bean.ScoreBean"> <id property="id" column="id"></id> <result property="subject" column="subject"></result> <result property="score" column="score"></result> <association property="studentBean" javaType="mybatis.bean.StudentBean" column="studentId"> <id property="id" column="id"></id> <result property="name" column="name"></result> <result property="address" column="address"></result> <result property="num" column="num"></result> </association> </resultMap> <select id="selectScoreByStudentId" resultMap="scoreMap"> select * from score s left join student t on s.studentId = t.id where studentId = #{studentId} </select> </mapper>
這個比較簡單,就不說了,就是寫了一個resultMap。我們來看一下兩條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"> <mapper namespace="mybatis.dao.ScoreMapper"> <resultMap id="scoreMap" type="mybatis.bean.ScoreBean"> <id property="id" column="id"></id> <result property="subject" column="subject"></result> <result property="score" column="score"></result> <association property="studentBean" javaType="mybatis.bean.StudentBean" select="mybatis.dao.StudentMapper.selectUser" column="studentId"> <id property="id" column="id"></id> <result property="name" column="name"></result> <result property="address" column="address"></result> <result property="num" column="num"></result> </association> </resultMap> <select id="selectScoreByStudentId" resultMap="scoreMap"> select * from score where studentId = #{studentId} </select> </mapper>
簡單解釋一下,其實和上面collection差不多的,select指定查詢sql位置,column執行傳遞過去的參數。
其余的insert,update,delete都差不多,我這里就放在一起說了。
| id | 命名空間中的唯一標識符,可被用來代表這條語句。 |
| parameterType | 將要傳入語句的參數的完全限定類名或別名。這個屬性是可選的,因為 MyBatis 可以通過類型處理器推斷出具體傳入語句的參數,默認值為未設置(unset)。 |
| flushCache | 將其設置為 true 后,只要語句被調用,都會導致本地緩存和二級緩存被清空,默認值:true(對於 insert、update 和 delete 語句)。 |
| timeout | 這個設置是在拋出異常之前,驅動程序等待數據庫返回請求結果的秒數。默認值為未設置(unset)(依賴驅動)。 |
| statementType | STATEMENT,PREPARED 或 CALLABLE 的一個。這會讓 MyBatis 分別使用 Statement,PreparedStatement 或 CallableStatement,默認值:PREPARED。 |
| useGeneratedKeys | (僅對 insert 和 update 有用)這會令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法來取出由數據庫內部生成的主鍵(比如:像 MySQL 和 SQL Server 這樣的關系數據庫管理系統的自動遞增字段),默認值:false。 |
| keyProperty | (僅對 insert 和 update 有用)唯一標記一個屬性,MyBatis 會通過 getGeneratedKeys 的返回值或者通過 insert 語句的 selectKey 子元素設置它的鍵值,默認值:未設置(unset)。如果希望得到多個生成的列,也可以是逗號分隔的屬性名稱列表。 |
| keyColumn | (僅對 insert 和 update 有用)通過生成的鍵值設置表中的列名,這個設置僅在某些數據庫(像 PostgreSQL)是必須的,當主鍵列不是表中的第一列的時候需要設置。如果希望使用多個生成的列,也可以設置為逗號分隔的屬性名稱列表。 |
| databaseId | 如果配置了數據庫廠商標識(databaseIdProvider),MyBatis 會加載所有的不帶 databaseId 或匹配當前 databaseId 的語句;如果帶或者不帶的語句都有,則不帶的會被忽略。 |
useGeneratedKeys=”true”這個相當來說配置的還是比較多的,也就是我們新增成功后,我們的對象可以返回我們插入成功的主鍵ID。
拼裝sql:
#{}:是預處理,也是一個占位符的方式來執行sql,${}是sql的拼接,我們其實可以這樣來寫。
@Select("select * from ${}_sys_log where id=#{condition}")
public SystemLog findSystemLog(String year,String condition);
也就是說,我們對日志sys_log表做了分庫分表,按照年份來區分的表,這時我們可以采用sql拼接的方式來做。
但盡力不要用拼接的方式來做,后面我將動態sql會說具體怎么來實現。${}容易被sql注入。所以我們盡力還用占位符的方式來處理我們的SQL。
然后就是我們的插件集成,還有緩存,下次博客我們來說說緩存吧。
忘記了,學mybatis的使用,推薦一個網站https://mybatis.org/mybatis-3/zh/index.html 上面挺全的(沒有源碼解析,源碼還得回來看我博客)。
最進弄了一個公眾號,小菜技術,歡迎大家的加入

