(一)需求,為什么要使用接口開發?
- 在測試用例中,在調用session的方法的時候,都會傳入要調用的SQL的namespace+id名稱,這不是必須的。可以只傳入id即可。但是,如果在mybatis的環境中有多個相同id的映射名稱,就會報錯。所以,一般情況下,調用方法最好還是使用namespace+id。
- 但是,namespace+id的使用方式很容易報錯,因為是string類型的,沒有檢查。所以,mybatis提供了一種非常好的設計方式來避免這種問題,即Mapper接口。
接口開發的規范:namespace的值=接口的包名+接口的類名
注意:
1、 包名 + 類名 = XXXMapper.xml中namespace的值
2、 接口中方法名 = mapper.xml中 具體的SQL語句定義的id值
3、 方法的返回值和參數要和映射文件中一致(當數據庫的字段名和對象的屬性名一致時,可以用簡單屬性resultType。但是當數據庫中的字段名稱和對象中的屬性名稱不一致時,就需要resultMap 屬性。)
/* <select id="all" resultType="User"> select * from user </select> */ public List<User> all(); //這是接口中的方法
(二)Mybatis怎么做的?
@Test public void testMapper(){ SqlSession session = MyBatisUtil.openSession(); try{ UserMapper mapper = session.getMapper(UserMapper.class); System.out.println(mapper.getClass().getName()); }finally{ session.close(); } }
打印結果:
$Proxy4
很簡單了,mybatis為接口做了一個動態代理。在執行UserMapper接口上面的方法時,參考接口的全路徑名,即可找到對應的UserMapper.xml,在執行接口上面的每一個方法的時候,實際上 就是在執行namespace+id,mybatis在根據定義的方法的元素,選擇調用合適的session的方法來執行,並傳入參數就可以。
使用Mapper接口的方式,在集成Spring+MyBatis也非常方便。因為我們可以直接把Mapper接口看作domain的dao接口了。
(三)接口開發的三個特點
1、 Mapper接口方法名和mapper.xml中定義sql的id值相同
2、 Mapper接口方法接收的參數類型和mapper.xml中定義的sql 的parameterType的類型相同
3、 Mapper接口方法的返回值類型和mapper.xml中定義的sql的resultType的類型相同
(四)自動匹配規范駝峰規則
數據庫中我們習慣使用全大寫,多個單詞用下划線隔開,而po對象,習慣使用java駝峰規則。那一個一個手工寫resultMap字段,浪費開發時間。Mybatis可以配置mapUnderscoreToCamelCase,實現自動映射。這個值默認為true。
1 sqlMapConfig.xml中配置settings
<?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> <settings> <setting name="mapUnderscoreToCamelCase" value="true" /> </settings> </configuration>
-
在XXXmapper文件中 resultMap配置autoMapping="true"
<resultMap type="cn.tedu.jk.domain.Contract" id="contractRM" autoMapping="true"> <id property="id" column="CONTRACT_ID"/> </resultMap>
注意:主鍵需要單獨寫,其它字段就可以直接利用駝峰規則自動映射。
(五)SQL模糊查詢
1 參數中直接加入%%(不好)
如果要發起一條SQL,where name like #{name},name手動傳入%大%這里就容易發生SQL注入問題
2 Sql中用CONCAT函數 (推薦) 三種數據庫的字符串拼接
Sql Server 中沒有Concat函數 拼接 直接用 + 號
Oracle 和 MySQL 可以用Concat進行拼接
<!-- where 2--> <select id="findone2" resultType="User" parameterType="map"> select <include refid="cols"></include>
from user <where> id=#{id} and addr=#{addr} and name like concat(concat('%',#{name}),'%') </where> </select>
(六)【重點】關聯關系
1 准備數據
1.3.1.1 用戶表user_info create table user_info( id int primary key auto_increment, user_name varchar(100), user_addr varchar(200), user_age int); set names gbk; insert into user_info values(null,’韓梅梅’,’上海’,20); insert into user_info values(null,’王海濤’,’北京’,30); insert into user_info values(null,’張慎政’,’河南’,10); 1.3.1.2 用戶擴展表user_extra create table user_extra( id int primary key auto_increment, user_id int, work varchar(100), salary double); insert into user_extra values(null,’1’,’程序員’,100000); insert into user_extra values(null, ’2’,’教師’,1000); insert into user_extra values(null, ’3’,’CTO’,100000); 1.3.1.3 訂單表orders create table orders( id int primary key auto_increment, user_id int, order_no int, order_desc varchar(100), price double); insert into orders values(null,1,100,’好評’,1000); insert into orders values(null,2,200,’優秀’,100); insert into orders values(null,1,300,’優秀’,100); insert into orders values(null,1,400,’優秀’,100);
2 封裝對象
public class UserInfo { //id映射 private int id; //user_name映射 private String userName; //user_addr映射 private String userAddr; //user_age映射 private int userAge;
自己生成一下get,set方法,和toString 方法 (Ecilipse快捷鍵 SHIFT+ALT+S)
}
public class UserExtra { //id映射 private int id; //work映射 private String work; //salary映射 private double salary; //user_id映射(對應user表的id) private int userId;
自己生成一下get,set方法,和toString 方法 (Ecilipse快捷鍵 SHIFT+ALT+S)
}
public class Orders { //id映射 private int id; //user_id映射 private int userId; //order_no映射 private int orderNo; //order_desc映射 private String orderDesc; //price映射 private double price;
自己生成一下get,set方法,和toString 方法 (Ecilipse快捷鍵 SHIFT+ALT+S)
}
3 根據用戶查詢一對一關系的用戶擴展信息,使用association + javaType
3.1改造UserInfo對象 (將UserExtra對象引入)
public class UserInfo { private int id; private String userName; private String userAddr; private int userAge; //一對一 private UserExtra userExtra;
自己生成一下get,set方法,和toString 方法 (Ecilipse快捷鍵 SHIFT+ALT+S)
}
3.2編寫UserInfoMapper.xml(引入核心配置文件中去!!association + javaType)
<?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="cn.tedu.dao.UserInfoDao"> <!-- 一對一的UserExtra信息 type="" 把數據封裝給哪個實體對象(全路徑) id="userExtraRM" 唯一標志 --> <resultMap type="cn.tedu.pojo.UserInfo" id="userExtraRM"> <!-- association用來描述一對一關系 property="userExtra" 在UserInfo中的屬性 javaType="" 關聯對象的類的全路徑... --> <association property="userExtra" javaType="cn.tedu.pojo.UserExtra"> <!-- 描述UserExtra信息... --> <id column="id" property="id" /> <result column="work" property="work" /> <result column="salary" property="salary" /> <result column="user_id" property="userId" /> </association> </resultMap> <!-- 根據用戶id查詢用戶詳情 --> <!-- 一對一的關聯查詢 resultMap="" 引用上面大的結果集,id值 --> <select id="getExtraByUserId" resultMap="userExtraRM"> select * from user_info t1, user_extra t2 where t1.id=t2.user_id and t1.id=#{id} </select> </mapper>
3.3 創建UserInfoDAO接口
public interface UserInfoDao { //根據用戶id查詢用戶的信息,一對一 public UserInfo getExtraByUserId(int userId); }
3.4測試代碼
public class ORMTest { // 1,讀取配置文件,創建ssf對象 SqlSessionFactory ssf; @Before public void init(){ try { InputStream inputStream = Resources.getResourceAsStream( "sqlMapConfig.xml"); ssf = new SqlSessionFactoryBuilder() .build(inputStream); } catch (IOException e) { e.printStackTrace(); } } //測試對象的一對一關系 @Test public void One2One(){ //創建sqlsession,執行SQL SqlSession session = ssf.openSession(); //接口開發 UserInfoDao dao = session.getMapper(UserInfoDao.class); //調用接口方法 UserInfo info = dao.getExtraByUserId(1); System.out.println(info); session.close(); } }
4 一對多 查詢用戶的所有訂單,使用collection + ofType
4.1改造UserInfo對象 (將UserExtra對象引入)
public class UserInfo { private int id; private String userName; private String userAddr; private int userAge; private UserExtra userExtra; //一對多 private List<Orders> orders;
自己生成一下get,set方法,和toString 方法 (Ecilipse快捷鍵 SHIFT+ALT+S)
}
4.2 改造UserInfoMapper.xml
<?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="cn.tedu.dao.UserInfoDao"> <!-- 一對多的關聯關系 type="" 結果集封裝到哪個對象身上 extends="userInfoRM" 和其他resultMap的關聯關系 --> <resultMap type="cn.tedu.pojo.UserInfo" id="ordersRM" extends="userInfoRM"> <!-- 多的一方Orders的對象信息 property="" UserInfo對象中的屬性名 ofType="" 關聯對象Orders的全路徑 --> <collection property="orders" ofType="cn.tedu.pojo.Orders"> <!-- 描述Orders的信息 --> <id column="id" property="id" /> <!-- 普通字段 --> <result column="user_id" property="userId" /> <result column="order_no" property="orderNo" /> <result column="order_desc" property="orderDesc" /> <result column="price" property="price" /> </collection> </resultMap> </mapper>
增加關聯查詢的SQL 注意:結果集中,不要出現同名的字段,否則封裝不成功!!如果出現重復字段,以結果集為准,重新映射column關系。 <!-- 根據用戶id查詢訂單信息 resultMap="ordersRM"引用其他resultMap,id值 --> <select id="getOrdersByUserId" resultMap="ordersRM"> select * from user_info t1, orders t2 where t1.id=t2.user_id and t1.id=#{id} </select>
4.3改造UserInfoDao接口
public interface UserInfoDao { //根據用戶id查詢用戶的信息,一對一 public UserInfo getExtraByUserId(int userId); //據用戶id查詢訂單信息 public List<UserInfo> getOrdersByUserId(int userId); }
4.4改造測試類
@Test public void One2Many(){ //創建sqlsession,執行SQL SqlSession session = ssf.openSession(); //接口開發 UserInfoDao dao = session.getMapper(UserInfoDao.class); //調用接口方法,根據用戶id查詢訂單 List<UserInfo> list = dao.getOrdersByUserId(1); for (UserInfo userInfo : list) { System.out.println(userInfo); } session.close(); }
相信一萬小時天才理論
最窮不過要飯,不死終會出頭!