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)數據庫設計如下
單純插入數據
(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)運行結果
插入後用新 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)運行結果
刪除數據
(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)運行結果
查詢所有對象-返回 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)運行結果
說明:
若指定的作爲 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)運行結果
$與#的區別
-
理論區別
$與#的區別是很大的。 #爲佔位符,而$爲字符串拼接符。
字符串拼接是將參數值以硬編碼的方式直接拼接到了 SQL 語句中。字符串拼接就會引發兩個問題: SQL 注入問題與沒有使用預編譯所導致的執行效率低下問題。 -
執行區別
- 應用場景
一般情況下,動態參數的值是由用戶輸入的,則不能使用拼接符$,因爲有可能會出現 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 表
(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>
運行結果如下:
使用結果映射 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>
運行結果如下: