Mybatis学习(4)单表的CURD操作

第一个例子就列举了简单插入的操作,接下来详细的描述每一个操作

1、搭建测试环境

有了之前的例子,这个是在之前的例子上面进行修改。

1.1 修改Dao接口IStudentDao

public interface IStudentDao {

	void insertStu(Student student);
	void insertStuCacheId(Student student);
	
	void deleteStuById(int id);
	
	void updateStu(Student student);

	List<Student> selectAllStudent();
	Map<String, Object> selectAllStudentMap();
	Student selectStudentById(int id);
	List<Student> selectStuByName(String name);
}

1.2 修改实现类StudentDaoImpl

public class StudentDaoImpl implements IStudentDao {
	private SqlSession sqlSession;
	
	public void insertStu(Student student) {
		try {
			sqlSession=MybatisUtil.getSqlSession();
			sqlSession.insert("insertStudent",student);
			sqlSession.commit();
		}finally{
			if(sqlSession!=null){
				sqlSession.close();
			}
		}	
	}
	
	public void insertStuCacheId(Student student) {
		try {
			sqlSession=MybatisUtil.getSqlSession();
			sqlSession.insert("insertStuCacheId",student);
			sqlSession.commit();
		}finally{
			if(sqlSession!=null){
				sqlSession.close();
			}
		}	
	}
	
	public void deleteStuById(int id) {
		try {
			sqlSession=MybatisUtil.getSqlSession();
			System.out.println("要删除的id"+id);
			//这里面的deleteStuById要和mapper里面的ID对应
			sqlSession.delete("deleteStuById",id);
			sqlSession.commit();
		}finally{
			if(sqlSession!=null){
				sqlSession.close();
			}
		}	
	}
	
	public void updateStu(Student student) {
		try {
			sqlSession=MybatisUtil.getSqlSession();
			//4.增删改查的操作
			sqlSession.update("updateStu",student);
			sqlSession.commit();
		}finally{
			if(sqlSession!=null){
				sqlSession.close();
			}
		}	
	}
	
	
	public List<Student> selectAllStudent() {
		List<Student> students = new ArrayList<Student>();
		try {
			sqlSession = MybatisUtil.getSqlSession();
			students = sqlSession.selectList("selectAllStudents");
			sqlSession.commit();
		} finally {
			if(sqlSession != null) {
				sqlSession.close();
			}
		}
		return students;
	}
	
	public Student selectStudentById(int id) {
		Student student=null;
		try {
			sqlSession = MybatisUtil.getSqlSession();
			student = sqlSession.selectOne("selectStudentById",id);
			sqlSession.commit();
		} finally {
			if(sqlSession != null) {
				sqlSession.close();
			}
		}
		return student;
	}
	
	
	public Map<String, Object> selectAllStudentMap() {
		Map<String,Object> map=new HashMap<String, Object>();
		try {
			sqlSession=MybatisUtil.getSqlSession();
			map=sqlSession.selectMap("selectAllStudents", "name");
		}finally{
			if(sqlSession!=null){
				sqlSession.close();
			}
		}
		
		return map;
	}
	public List<Student> selectStuByName(String name) {
		List<Student> students = null;
		try {
			sqlSession = MybatisUtil.getSqlSession();
			students = sqlSession.selectList("selectStuByName",name);
			sqlSession.commit();
		} finally {
			if(sqlSession != null) {
				sqlSession.close();
			}
		}
		return students;
	}
}

这里需要注意的是,增删改的操作都需要对事务的提交,也就是执行sqlSession.commit()。但是查询操作不需要。

1.3 修改测试类MyTest

public class MyTest {
	//由于增删改查都需要StudentDaoImpl,所以将其设置2全局变量。	
	private IStudentDao dao ;
	
	@Before
	public void testBefore(){
		dao = new StudentDaoImpl();
	}
	
	@Test
	public void testinsertStu(){	
		Student student = new Student("张三",23,93.5);
		dao.insertStu(student);	
	}

	@Test
	public void testinsertStuCacheId(){
		Student student = new Student("冯冬冬",20,97.5);
		System.out.println("插入之前的id:"+student);
		dao.insertStuCacheId(student);
		System.out.println("插入之后的id:"+student.getId());
	}
	
	@Test
	public void testDelete(){
		dao.deleteStuById(30);
	}
	@Test
	public void testUpdate(){
		Student student = new Student("王胜男1",19,96.5);
		student.setId(22);
		dao.updateStu(student);
	}
	
	//选出数据库中所有的对象
	@Test
	public void testselectAllStudent() {
		System.out.println("===========");
		List<Student> students = dao.selectAllStudent();
		
		for (Student student : students) {
			System.out.println(student);
		}
	}
	
	//根据id号选出学生
	@Test
	public void testselectStudentById() {
		Student student = dao.selectStudentById(24);	
		System.out.println(student);
	}
	
	//根据名字选出学生
	@Test
	public void testselectStuByName() {
		List<Student> students = dao.selectStuByName("冯");
		for (Student student : students) {
			System.out.println(student);
		}
	}
	//根据map选出学生
	@Test
	public void testselectAllStudentMap() {
		Map<String, Object> map=dao.selectAllStudentMap();	
		System.out.println(map.get("冯冬冬"));
	}
}

1.4 修改mapper

<?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="test">
	<!-- parameterType已经定义了别名 -->
	<insert id="insertStudent" >
		insert into student(name,age,score) values(#{name},#{age},#{score})
	</insert>
	
	<insert id="insertStuCacheId" >
		insert into student(name,age,score) values(#{name},#{age},#{score})
		<!-- order:指定id的生成与插入语句的顺序关系 -->
		<selectKey resultType="int" keyProperty="id" order="AFTER">
		<!-- 这里有两种方式可以选择 -->
		<!-- 1、select last_insert_id() -->
		<!-- 2、select @@identity -->
		select @@identity
		</selectKey>
	</insert>
	
	<!-- id里面的内容是接口里面的方法名 ,提供给别人使用-->
	<delete id="deleteStuById">
		delete from student where id=#{xxx}  
	</delete>
	
	<update id="updateStu">
		update student set name=#{name},age=#{age},score=#{score} where id=#{id}
	</update>
	
	<select id="selectAllStudents" resultType="com.test.beans.Student">
		select * from student
	</select>
	
	<select id="selectStudentById" resultType="com.test.beans.Student">
		select * from student where id=#{id}
	</select>

	<select id="selectStuByName" resultType="com.test.beans.Student">
		<!-- 这种查询方式表示只要含有xxx都会被查询到 -->
		<!-- 下面这种方式推荐使用,可以方式sql注入。动态参数 -->
		select * from student where name like '%' #{xxx} '%'
		<!--  select * from student where name like concat('%',#{xxx},'%')-->
		
		<!-- 下面这种情况表示纯粹的字符串拼接,在输出结果里面没有参数显示:这种情况不建议使用 -->
		<!--  select * from student where name like '%${value}%'-->
	</select>
</mapper>

2 增删改查操作的说明

2.1 插入:单纯插入数据

<insert id="insertStudent" >
		insert into student(name,age,score) values(#{name},#{age},#{score})
	</insert>
  • id:该SQL语句的唯一标识,java代码中要使用这个标识,也就是在接口的实现类中:、

  • #{}:对指定参数类型属性值的引用。其底层是通过反射机制,调用Student类相关属性的get方法来获取值得。因为底层使用的是反射,所以这里使用的是类的属性名,而不是表的字段名。也就是使用#{name}中的name对应Student学生类中的name属性,而不是DB数据库中的表的name字段。

2.2 插入:插入后用新id初始化被插入对象

<insert id="insertStuCacheId" >
		insert into student(name,age,score) values(#{name},#{age},#{score})
		<!-- order:指定id的生成与插入语句的顺序关系 -->
		<selectKey resultType="int" keyProperty="id" order="AFTER">
		    <!-- 这里有两种方式可以选择 -->
		    <!-- 1、select last_insert_id() -->
		    <!-- 2、select @@identity -->
		    select @@identity
		</selectKey>
</insert>

mysql中在插入语句后执行如下语句,则会输出新插入记录的id

或者是

映射文件的<insert/>标签,有一个字标签<selectKey/>获取新插入记录的主键值,上面的那两种写法都可以完成。

<selectKey resultType="int" keyProperty="id" order="AFTER">
	<!-- 这里有两种方式可以选择 -->
    <!-- 1、select last_insert_id() -->
    <!-- 2、select @@identity -->
    select @@identity
</selectKey>
  • resultType:指出获取的主键的类型
  • keyProperty:指出主键在java类(Student的id字段)对应的属性名。此处会将获取的主键值直接封装到被插入的Student对象中,也就是dao中insert()方法的第二个参数对象中。
  • order:指出id的生成相对于insert语句的执行是在前还是在后。mysql数据表中的id都是先执行insert再生成id。所以需要设置AFTER。但是Oracle数据库表中的id,则是在insert方法之前生成,所以需要设置成BEFORE。当前的Mybatis版本,可以没有order,DBMS会自动选择其值。

此时我们可以修改测试类:

问题:id是何时获取到的?

测试结果2证明:插入操作还没有提交的时候已经有了id。说明了一个问题:无论插入操作是提交还是回滚,DB均会为insert的记录分配id,即使发生回滚,这个id也已经被使用。后面在插入时候,这个id就不能用了。也就是说,主键值得生成至于insert语句是否执行有关,而与最终是否提交无关。

测试:

 

2.3 删除:删除数据

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

注意:这里的#{xxx}并没有写id,而是任意值。为什么呢?因为此时这个#{xxx}就是一个占位符,代表sqlSession.delete方法的第二个操作。

接下来看实现:

看测试类:

    @Test
	public void testDelete(){
		dao.deleteStuById(30);
	}

2.4 修改:修改数据

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

注意:这里的#{}中,必须要填写与update()方法所传入的第二个参数student对象的属性名称,不能随意填写。

看测试:

@Test
	public void testUpdate(){
		Student student = new Student("王胜男1",19,96.5);
		student.setId(22);
		dao.updateStu(student);
	}

2.5 查询:

2.5.1 查询所有对象-返回list

<select id="selectAllStudents" resultType="com.test.beans.Student">
		select * from student
</select>

注意:resultType属性并非指查询结果集最后的类型,而是查出的每一条记录的类型。这里的resultType使用的是全限定性类名。对于一个映射文件来说,一般情况下是对一个类的操作都放在同一个映射文件mapper.xml中。所以一个映射文件出现的类一般是相同的。而每一个需要指定类名的地方若都指定全限定类名会比较麻烦,因此推荐使用别名。

注册类的别名:有两种方式

再修改映射文件

<select id="selectAllStudents" resultType="Student">
		select * from student
</select>

修改测试类:

//选出数据库中所有的对象
	@Test
	public void testselectAllStudent() {
		System.out.println("===========");
		List<Student> students = dao.selectAllStudent();
		
		for (Student student : students) {
			System.out.println(student);
		}
	}

2.5.2 查询所有对象-返回map

1、映射文件不需要修改

2、修改实现类

	public Map<String, Object> selectAllStudentMap() {
		Map<String,Object> map=new HashMap<String, Object>();
		try {
			sqlSession=MybatisUtil.getSqlSession();
			map=sqlSession.selectMap("selectAllStudents", "name");
		}finally{
			if(sqlSession!=null){
				sqlSession.close();
			}
		}
		
		return map;
	}

3、修改测试类

//根据map选出学生
	@Test
	public void testselectAllStudentMap() {
		Map<String, Object> map=dao.selectAllStudentMap();	
		System.out.println(map.get("冯冬冬"));
	}

说明:若指定的作为key的属性值在DB中并不唯一,则后面的记录值会覆盖前面的值。即指定key的value值,一定是DB中该同名属性的最后一条记录值。

2.5.3 根据id查询单个对象

	<select id="selectStudentById" resultType="com.test.beans.Student">
		select * from student where id=#{id}
	</select>

接口的实现类如下:

测试类如下:

//根据id号选出学生
	@Test
	public void testselectStudentById() {
		Student student = dao.selectStudentById(24);	
		System.out.println(student);
	}

2.5.4 模糊查询

映射文件:

	<select id="selectStuByName" resultType="com.test.beans.Student">
		<!-- 这种查询方式表示只要含有xxx都会被查询到 -->
		<!-- 下面这种方式推荐使用,可以方式sql注入。动态参数 -->
		select * from student where name like '%' #{xxx} '%'
		<!--  select * from student where name like concat('%',#{xxx},'%')-->
		
		<!-- 下面这种情况表示纯粹的字符串拼接,在输出结果里面没有参数显示:这种情况不建议使用 -->
		<!--  select * from student where name like '%${value}%'-->
	</select>

第一种:

在进行模糊查询的时候,需要进行字符串的拼接。SQL中的字符串的拼接使用的是函数concat(args1,args2,...)。注意不能使用java的字符串拼接+。

第二种:

以上两种方式等效,都是动态参数的形式出现在SQL中

第三种:

注意:这种方式是纯粹的字符串拼接,直接将参数拼接到了SQL语句中。这种方式可能会发生SQL注入。

实现类:

测试类:

//根据名字选出学生
	@Test
	public void testselectStuByName() {
		List<Student> students = dao.selectStuByName("冯");
		for (Student student : students) {
			System.out.println(student);
		}
	}

$与#的区别:

A:理论区别

$与#的区别是很大的,#表示占位符,$表示字符串拼接符

字符串拼接是将参数以硬编码的方式直接拼接到了SQL语句中。字符串拼接就会引发两个问题:sql注入与没有使用预编译所导致的执行效率低下问题。什么是sql注入和sql预编译呢?链接先放这,过两天整理

占位符的引用很好的解决了以上两个问题。

B:执行区别

先看占位符(1)

再看占位符(2)

再看拼接符

C:应用场景

一般情况下,动态参数的值是由用户输入的则不能使用拼接符$,因为有可能发生SQL注入,若动态参数的值是由系统计算生成的,则可以使用拼接符。但这样虽然不会发生SQL注入,但是带来了效率低下的问题。

 

OK,单表的操作就结束了,相比之下多表的操作比较麻烦,但是以上讨论的问题比较理想化,下一遍看当表的字段名字和类的属性名不一致怎么办的问题。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值