MyBatis的CURD操作(Dao接口實現類)

CURD 操作,即指對數據庫中實體對象的增 Create、改 Update、查 Read、刪 Delete 操作。

自定義 Dao 接口實現類

項目實例

(1)定義實體類

public class Student {
	private Integer id;
	private String name;
	private int age;
	private double score;

(2)定義 Dao 接口

public interface IStudentDao {
	void insertStudent(Student student);
	void insertStudentCacheId(Student student);
	
	void deleteStudentById(int id);
	void updateStudent(Student student);
	
	List<Student> selectAllStudents();
	Map<String, Student> selectStudentMap();
	
	Student selectStudentById(int id);
	Student selectStudentById(Map<String, Object> map);
	
	List<Student> selectStudentsByName(String name);

}

(3)定義 Dao 實現類

public class StudentDaoImpl implements IStudentDao {
	
	private SqlSession sqlSession;

	@Override
	public void insertStudent(Student student) {
		try {
			//使用工具類獲取SqlSession對象
			sqlSession = MyBatisUtil.getSqlSession();
			//操作
			sqlSession.insert("insertStudent",student);
			//SqlSession提交
			sqlSession.commit();
		} finally {
			//SqlSession關閉,添加了close()不用作事務回滾
			if (sqlSession != null) 
				sqlSession.close();
			
		}
		
	}

(4)創建工具類

public class MyBatisUtil {
	private static SqlSessionFactory sqlSessionFactory;

	public static SqlSession getSqlSession() {
		try {
			InputStream is = Resources.getResourceAsStream("mybatis.xml");
			if (sqlSessionFactory == null) {
				sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
			}
			return sqlSessionFactory.openSession();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

}

(5)定義測試類

public class MyTest {
	private StudentDaoImpl dao;
	
	@Before
	public void setUp() {
		dao= new StudentDaoImpl();
	}

}

(6)數據庫設計如下

{% asset_img curd01.jpg %}

單純插入數據

(1)修改映射文件

	<insert id="insertStudent"
	parameterType="com.huang.beans.Student">
		insert into 
		student(name,age,score) 
		values(#{name},#{age}, #{score})
	</insert>
  • id:該 SQL 語句的唯一標識, Java 代碼中要使用該標識
  • #{ }:對指定參數類型屬性值的引用。其底層是通過反射機制,調用 Student 類相關屬性的 get 方法來獲取值的。因爲底層使用的是反射,所以這裏使用的是類的屬性名,而非表的字段名。

(2)修改 Dao 實現類

使用 SqlSession 對象的 insert()方法。該方法默認返回 DB 中受影響條數。其方法原型爲:insert(String id, Object obj)。

@Override
	public void insertStudent(Student student) {
		try {
			//使用工具類獲取SqlSession對象
			sqlSession = MyBatisUtil.getSqlSession();
			//操作
			sqlSession.insert("insertStudent",student);
			//SqlSession提交
			sqlSession.commit();
		} finally {
			//SqlSession關閉,添加了close()不用作事務回滾
			if (sqlSession != null) {
				sqlSession.close();
			}
		}
		
	}

注意:
執行完對 DB 的修改操作,必須要做 SqlSession 的提交。否則,修改將無法同步到 DB 中。因爲使用無參的 openSession()方法已經將事務的自動提交功能給關閉了。

(3)修改測試類

@Test
	public void test01() {
		for (int i = 1; i < 10; i++) {
			Student student = new Student("n_" + i, 15 + i,85.5 + i);
			dao.insertStudent(student);
			
		}
	}

(4)運行結果

{% asset_img curd02.jpg %}

插入後用新 id 初始化被插入對象

(1)修改映射文件
映射文件的標籤中,有一個子標籤用於獲取新插入記錄的主鍵值。

	<insert id="insertStudentCacheId"
	parameterType="com.huang.beans.Student">
		insert into 
		student(name,age,score) 
		values(#{name},#{age}, #{score})
		<selectKey resultType="int" keyProperty="id" order="AFTER">
		    select @@identity
		</selectKey>
	</insert>
  • resultType:指出獲取的主鍵的類型。
  • keyProperty:指出主鍵在 Java 類中對應的屬性名。此處會將獲取的主鍵值直接封裝到被插入的 Student 對象中,即 dao 中 insert()方法的第二個參數對象中。
  • order:指出 id 的生成相對於 insert 語句的執行是在前還是在後。 MySql 數據庫表中的 id,均是先執行 insert 語句,而後生成 id, 所以需要設置爲 AFTER; Oracle 數據庫表中的 id,則是在 insert 執行之前先生成,所以需要設置爲 BEFORE。 當前的 MyBatis 版本,不指定 order 屬性,則會根據所用 DBMS,自動選擇其值。

(2)修改 Dao 實現類

@Override
	public void insertStudentCacheId(Student student) {
		try {
			//使用工具類獲取SqlSession對象
			sqlSession = MyBatisUtil.getSqlSession();
			//操作
			sqlSession.insert("insertStudentCacheId",student);
			//SqlSession提交
			sqlSession.commit();
		} finally {
			//SqlSession關閉,添加了close()不用作事務回滾
			if (sqlSession != null) {
				sqlSession.close();
			}
		}
	}

(3)修改測試類

@Test
	public void test02(){
		Student student = new Student("張三", 28, 93.5);
		
		System.out.println("插入前student = " + student);
		dao.insertStudentCatchId(student);
		System.out.println("插入後student = " + student);
		}

(4)運行結果

{% asset_img curd03.jpg %}

刪除數據

(1)修改映射文件

	<delete id="deleteStudentById">
	    delete from student where id=#{xxx}
	</delete>

注意:
這裏的動態參數 id 所賦值爲#{xxx}。這個#{xxx}表示這就是個佔位符,代表 delete()方法的第二個參數。 #{ }中可以放任意值,無需要與 delete()方法的第二個參數值相同。

(2)修改 Dao 實現類

@Override
	public void deleteStudentById(int id) {
		try {
			//使用工具類獲取SqlSession對象
			sqlSession = MyBatisUtil.getSqlSession();
			//操作
			sqlSession.delete("deleteStudentById",id);
			//SqlSession提交
			sqlSession.commit();
		} finally {
			//SqlSession關閉,添加了close()不用作事務回滾
			if (sqlSession != null) {
				sqlSession.close();
				
			}
			
		}
	}

(3)修改測試類

@Test
	public void test03() {
		dao.deleteStudentById(5);
	}

修改數據

(1)修改映射文件

	<update id="updateStudent">
	    update student
	    set name=#{name}, age=#{age}, score=#{score}
	    where id=#{id}
	</update>

注意:
這裏的#{ }中,必須要填寫 update()方法所傳第二個參數 student 對象的屬性名稱,不能隨意填寫。

(2)修改 Dao 實現類

@Override
	public void updateStudent(Student student) {
		try {
			//使用工具類獲取SqlSession對象
			sqlSession = MyBatisUtil.getSqlSession();
			//操作
			sqlSession.delete("updateStudent",student);
			//SqlSession提交
			sqlSession.commit();
		} finally {
			//SqlSession關閉,添加了close()不用作事務回滾
			if (sqlSession != null) {
				sqlSession.close();
				
			}
			
		}
	}

(3)修改測試類

	@Test
	public void test04() {
		Student student = new Student("張小三", 18, 99.5);
		student.setId(1);
		
		dao.updateStudent(student);
	}

查詢所有對象-返回 List

(1)修改映射文件

	<select id="selectAllStudents" resultType="Student">
		select id,name,age,score from student
	</select>

注意:
resultType 屬性並非指查詢結果集最後的類型,而是每查出 DB 中的一條記錄,將該記錄封裝成爲的對象的類型。

(2)註冊類的別名

		<!-- 將指定包中所有類的簡單類名當作其別名 ,type:全限定性類名,alias:別名-->
		<package name="com.huang.beans"/>
	</typeAliases>

(3)修改 Dao 實現類

完成 Dao 實現類的 selectAllStudent()方法。 使用 SqlSession 的 selectList() 方法完成查詢操作。 該方法會將查詢出的每條記錄封裝爲指定類型對象後,再將最後的結果集封裝爲 List 返回。 方法原型爲: List selectList (String statement)。

statement:映射文件中配置的 SQL 語句的 id。

@Override
	public List<Student> selectAllStudents() {
		List<Student> students = null;
		try {
			sqlSession = MyBatisUtils.getSqlSession();
			students = sqlSession.selectList("selectAllStudents");
			//sqlSession.commit();
		} finally {
			if(sqlSession != null) {
				sqlSession.close();
			}
		}
		return students;
	}

說明:
在寫查詢時,由於不是對 DB 中數據進行修改,所以無需進行 SqlSession 的提交。但最終 SqlSession 對象還是需要關閉的。

(4)修改測試類

	//查詢所有:返回List
	@Test
	public void test05() {
		List<Student> students = dao.selectAllStudents();
		for (Student student : students) {
			System.out.println(student);
		}
	}

(5)運行結果

{% asset_img curd04.jpg %}

查詢所有對象-返回 Map

(1)修改 Dao 實現類

完成 Dao 實現類的 selectStudentMap()方法。 使用 SqlSession 的 selectMap()方法完成查詢操作。 該查詢方法會將查詢出的每條記錄先封裝爲指定對象,然後再將該對象作爲 value,將該對象的指定屬性所對應的字段名作爲 key 封裝爲一個 Map 對象。 方法原型爲: Map<Object,Object> selectMap (String statement, String mapKey)。

  • statement:映射文件中配置的 SQL 語句的 id。
  • mapKey:查詢出的 Map 所要使用的 key。這個 key 爲數據表的字段名。查詢出的結果是一個 Map,每行記錄將會對應一個 Map.entry 對象,該對象的 key 爲指定字段的值, value爲記錄數據所封裝的對象。
@Override
	public Map<String, Object> selectAllStudentsMap() {
		Map<String, Object> map = new HashMap<>();
		try {
			sqlSession = MyBatisUtils.getSqlSession();
			map = sqlSession.selectMap("selectAllStudents", "name");
		} finally {
			if(sqlSession != null) {
				sqlSession.close();
			}
		}
		return map;
	}

(2)修改測試類

	@Test
	public void test06() {
		Map<String, Object> map = dao.selectAllStudentsMap();
		System.out.println(map.get("張三"));
	}

(3)運行結果

{% asset_img crud05.jpg %}

說明:
若指定的作爲 key 的屬性值在 DB 中並不唯一,則後面的記錄值會覆蓋掉前面的值。即指定 key 的 value 值,一定是 DB 中該同名屬性的最後一條記錄值。

查詢單個對象

(1)修改映射文件

	<!-- 符號jjj表示佔位符 -->
	<select id="selectStudentById" resultType="Student">
		select id,name,age,score from student where id=#{jjj}
	</select>

(2)修改 Dao 實現類

使用 SqlSession 的 selectOne()方法。其會將查詢的結果記錄封裝爲一個指定類型的對象。方法原型爲: Object selectOne (String statement, Object parameter)

  • statement:映射文件中配置的 SQL 語句的 id
  • parameter:查詢條件中動態參數的值
	@Override
	public Student selectStudentById(int id) {
		Student student = null;
		try {
			sqlSession = MyBatisUtils.getSqlSession();
			student = sqlSession.selectOne("selectStudentById", id);
		} finally {
			if(sqlSession != null) {
				sqlSession.close();
			}
		}
		return student;
	}

(3)修改測試類

	@Test
	public void test07() {
		Student student = dao.selectStudentById(22);
		System.out.println(student);
	}

模糊查詢

(1)修改映射文件

	<select id="selectStudentsByName" resultType="Student">
		select id,name,age,score from student where name like '%' #{xxx} '%'
	</select>

注意:
在進行模糊查詢時, 需要進行字符串的拼接。 SQL 中的字符串的拼接使用的是函數 concat(arg1,arg2,…)。注意不能使用 Java 中的字符串連接符+。

(2)修改 Dao 實現類

	@Override
	public List<Student> selectStudentsByName(String name) {
		List<Student> students = null;
		try {
			sqlSession = MyBatisUtils.getSqlSession();
			students = sqlSession.selectList("selectStudentsByName", name);
		} finally {
			if(sqlSession != null) {
				sqlSession.close();
			}
		}
		return students;
	}

(3)修改測試類

	@Test
	public void test08() {
		List<Student> students = dao.selectStudentsByName("張");
		for (Student student : students) {
			System.out.println(student);
		}
	}

(4)運行結果

{% asset_img curd06.jpg %}

$與#的區別

  1. 理論區別
    $與#的區別是很大的。 #爲佔位符,而$爲字符串拼接符。
    字符串拼接是將參數值以硬編碼的方式直接拼接到了 SQL 語句中。字符串拼接就會引發兩個問題: SQL 注入問題與沒有使用預編譯所導致的執行效率低下問題。

  2. 執行區別

{% asset_img curd07.jpg %}
在這裏插入圖片描述

  1. 應用場景

一般情況下,動態參數的值是由用戶輸入的,則不能使用拼接符$,因爲有可能會出現 SQL 注入;若動態參數的值是由系統計算生成的,則可以使用拼接符$。 但這樣雖然不存在 SQL 注入的風險,但仍存在執行效率問題。

根據 Map 進行查詢

mapper 中 SQL 語句的動態參數也可以是 Map 的 key。

(1)修改映射文件

	<select id="selectStudentByMap" resultType="Student">
	    select * from student where id=#{studentId}
	</select>

(2)修改 Dao 實現類

	@Override
	public Student selectStudentByMap(Map<String, Object> map) {
		Student student = null;
		try {
			
			sqlSession = MyBatisUtils.getSqlSession();
			student = sqlSession.selectOne("selectStudentByMap");
		} finally {
			if (sqlSession != null) {
				sqlSession.close();
				
			}
		}
		return student;
	}

(3)修改測試類

	@Test
	public void test09() {
		Student student = new Student();
		student.setId(6);
		
		Map<String, Object> map = new HashMap<String,Object>();
		map.put("studentId", 10);
		map.put("student", student);
		
		student = dao.selectStudentByMap(map);
		System.out.println(student);
	}

屬性名與查詢字段名不相同

resultType 可以將查詢結果直接映射爲實體 Bean 對象的條件是, SQL 查詢的字段名與實體 Bean 的屬性名一致。 因爲在將查詢結果轉換爲指定類型對象時,系統自動將查詢結果字段名稱作爲對象的屬性名, 通過反射機制完成對象的創建。當 SQL 查詢結果的字段名和實體 Bean 的屬性名不一致時, 將無法創建出需要類型的對象。

項目實例

(1)修改 student 表

{% asset_img curd09.jpg %}

(2)修改 Dao 接口

public interface IStudentDao {
	Student selectStudentById(int id);
}

(3)定義 Dao 實現類

public class StudentDaoImpl implements IStudentDao {

	private SqlSession sqlSession;

	@Override
	public Student selectStudentById(int id) {
		Student student = null;
		try {
			sqlSession = MyBatisUtils.getSqlSession();
			student = sqlSession.selectOne("selectStudentById", id);
		} finally {
			if (sqlSession != null) {
				sqlSession.close();
				
			}
		}
		return student;
	}

}

(4)修改測試類

public class MyTest {
	
	private IStudentDao dao;
	
	@Before
	public void before() {
		dao = new StudentDaoImpl();
	}

	@Test
	public void test01() {
		Student student = dao.selectStudentById(1);
		System.out.println(student);
	}
}

查詢字段使用別名

雖然屬性名稱與表中字段名稱不一致,但可以爲查詢結果的字段名稱賦予別名,讓別名與實體 Bean 的屬性名相同。這樣框架也可以根據查詢結果利用反射機制將對象創建。

在映射文件 mapper 中添加如下映射。

	<select id="selectStudentById" resultType="Student">
	    select tid id,tname name,tage age,score from student where tid=#{xxx}
	</select>

運行結果如下:

{% asset_img curd10.jpg %}

使用結果映射 resultMap

可以使用結果映射 resultMap(這裏的 Map 是映射 mapper 的意思) 來建立映射關係,完成由字段到屬性的映射,達到將查詢結果封裝爲對象的目的。 resultMap 是對 resultType的增強。

修改映射文件 mapper.xml。

    <resultMap type="Student" id="studentMapper">
        <id column="tid" property="id"/>
        <result column="tname" property="name"/>
        <result column="tage" property="age"/>
    </resultMap>
	
	<select id="selectStudentById" resultMap="studentMapper">
	    select tid,tname,tage,score 
	    from student where tid=#{xxx}
	</select>

運行結果如下:

{% asset_img curd11.jpg %}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章