傳統的dao層編寫
以前編寫dao層,先新建一個包com.chy.dao,再寫接口StudentDao:
public interface StudentDao { public void insertStudent(Student student); public void updateStudent(Student student, Integer id); public Student selectStudent(Integer id); }
接着寫實現類StudentDaoImpl:
public class StudentDaoImpl implements StudentDao { @Override public void insertStudent(Student student) { } @Override public void updateStudent(Student student, Integer id) { } @Override public Student selectStudent(Integer id) { return null; } }
MyBatis的dao層編寫
MyBatis不這樣編寫dao。MyBatis的dao由2部分組成:映射文件、映射文件對應的接口。
新建一個包com.chy.mapper,包下新建接口StudentMapper:
public interface StudentMapper { public void insertStudent(Student student); public Student selectStudent(Integer id); }
包下新建此接口對應的映射文件StudentMapper.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="com.chy.mapper.StudentMapper"> <insert id="insertStudent" parameterType="com.chy.pojo.Student"> INSERT INTO student_tb(name,age,score)VALUES (#{name},#{age},#{score}) </insert> <select id="queryById" parameterType="Integer" resultType="Student"> SELECT * FROM student_tb WHERE id=#{id} </select> </mapper>
- 映射文件的文件名、namespace要與接口名相同,面向接口編程。
- id要與接口中的方法名相同
- 參數類型、返回值類型要與接口中的一致
- 接口中的方法最多只能有一個參數,因為映射文件的參數類型最多只能有一個
mapper包相當於傳統方式的dao包,映射文件相當於接口的實現類。
MyBatis dao層的使用
在mybatis全局配置文件中引入映射文件。
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession=sqlSessionFactory.openSession(); //通過mapper來調用接口中的方法,操作數據庫 //參數是mapper接口類的class對象 StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); //插入 Student student1 = new Student(); student1.setName("chy"); mapper.insertStudent(student1); //查詢 Student student2 = mapper.queryById(1); System.out.println(student2); sqlSession.commit(); sqlSession.close();
說明
Mapper接口不是必需的。
如果不寫Mapper接口,那只能通過sqlSession.selectOne()之類的方式操作數據庫;
編寫了Mapper接口,才可以通過Mapper接口來操作數據庫,sqlSession.getMapper(),實質是動態代理。
傳入包裝類型的參數
有時候我們需要傳入多個參數,比如
- 查詢age>20、score>90的學生,需要傳入2個Integer型的參數
- 查詢某本書在這一周的銷量,需要傳入一個pojo類:Book,還需要傳入一個參數表示這一周以內。
- 要查詢某用戶購買某輛汽車的訂單信息,需要傳入2個pojo類:User、Car
這種傳入多個參數的情況在復雜的條件查詢中比較常見,尤其是多表查詢。
mybatis最多只能傳入一個參數,怎么辦?
可以把要傳入的參數包裝一下,放在一個包裝類中,傳入包裝類即可。
新建包com.chy.vo,包下新建包裝類UserQueryVO,將要傳入的參數寫為成員變量,並提供getter、setter方法:
public class UserQueryVO { private User user; private Car car; public User getUser() { return user; } public void setUser(User user) { this.user = user; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } }
vo:value object 值對象
po:persist object 持久化對象,與數據表對應。
pojo:plain ordinary java object 簡單的Java對象
在com.chy.mapper包下新建UserMapper接口,編寫對應的映射文件實現數據庫操作。
public interface UserMapper { public Order queryOrder(UserQueryVO vo); }
<mapper namespace="com.chy.mapper.UserMapper"> <select id="queryOrder" parameterType="com.chy.vo.UserQueryVO" resultType="com.chy.pojo.Order"> SELECT * FROM order_tb WHERE order_tb.user_id=#{user.id} AND order_tb.car_name=#{car.name} </select> </mapper>
#{}中的user、car是vo的屬性,這2個屬性本身也是對象,可通過.來訪問user、car的屬性。
使用:
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession=sqlSessionFactory.openSession(); Car car = new Car(); car.setName("寶馬X6"); User user = new User(); user.setId(1); //要傳入的包裝類 UserQueryVO vo = new UserQueryVO(); vo.setCar(car); vo.setUser(user); UserMapper mapper = sqlSession.getMapper(UserMapper.class); //傳入包裝類進行查詢 Order order = mapper.queryOrder(vo); System.out.println(order);
使用Map傳入多個參數
除了可以使用包裝類傳入多個參數,也可以使用Map傳入多個參數。
Mapper接口:
public interface UserMapper { public Order queryOrder(Map<String,Object> map); }
這個是Mapper接口,所以參數通常寫接口,不寫具體的實現類,讓耦合是接口層次的。
要傳入的參數的數據類型不同,寫成Object。
映射文件:
<mapper namespace="com.chy.mapper.UserMapper"> <select id="queryOrder" parameterType="HashMap" resultType="com.chy.pojo.Order"> SELECT * FROM order_tb WHERE order_tb.user_id=#{user.id} AND order_tb.car_name=#{car.name} </select> </mapper>
#{}中的user、car是map的key,得到對應的value(對象),再通過.獲取屬性值。
使用:
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession=sqlSessionFactory.openSession(); Car car = new Car(); car.setName("寶馬X6"); User user = new User(); user.setId(1); //要傳入的map HashMap<String,Object> map = new HashMap<>(); map.put("car", car); map.put("user", user); UserMapper mapper = sqlSession.getMapper(UserMapper.class); //傳入map進行查詢 Order order = mapper.queryOrder(map); System.out.println(order);
與使用包裝類傳入多個參數相比,使用map不需要創建vo類,更加簡單。
使用List傳入多個參數
<update id="updateMoney" parameterType="list"> <!--傳入map,直接通過key來引用--> update user_tb set money=#{list[1]} where id=#{list[0]} </update>
默認以list代表列表名。
使用@Param直接傳入多個參數
不使用@Param,則只能有一個參數;使用@Param,可以有多個參數。
mapper接口:
public interface UserMapper { public double queryMoneyById(int id); public void updateMoney(@Param("id") int id, @Param("money") double money); }
映射文件:
<update id="updateMoney"> <!--傳入map,直接通過key來引用--> update user_tb set money=#{money} where id=#{id} </update>
不設置參數類型,@Param("value")、#{value}這2個value要相同,通過這個值來綁定參數。