Mybatis中的传参以及增删改查
参数传递
参数传递分为单个参数、多个参数。
单个参数直接传递
- 需要在代理接口中声明一个方法
Student findStudent(int id);
- 在对应的studentMapper.xml中:
<select id="findStudent" parameterType="int" resultType="com.ffyc.mybatis.modle.Student">
select name,gender from student where id = #{id}
</select>
注意:select中的id应当与代理接口中的方法名相同,parameterType表示传过来的参数的类型,resultType表示返回值的类型。
- 测试:
public void test(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student = studentDao.findStudent(1);
System.out.println(student);
sqlSession.close();
}
传递多个参数
传递多个参数时需要在代理接口中使用@Param(“id”)绑定,其他步骤不变。
如:
Student selectStudent(@Param("name") String name , @Param("id") int id);
如果参数过多,并且具有一定的规范,可以传递一个对象,此时就需要使用parameterType参数进行定义类型,如:
//代理接口中
void insert(Student student);
<insert id="insert" parameterType="Student">
insert into student (name,gender) values (#{name},#{gender})
</insert>
注意:parameterType属性可以直接写Student是因为在mybatisConfig.xml中使用了别名配置:
<typeAliases>
<package name="com.ffyc.mybatis.modle"/>
</typeAliases>
新增
在上面的案例中已经有新增的例子了
新增时如果只将代理对象中的方法声明为int类型的返回值时返回的是执行此操作改变的行数。
//代理接口中
int insert(Student student);
在测试中执行完测试方法后数据库表的数据并没有变化,是因为我们使用的是JDBC的事物管理,在所打印的日志“Setting autocommit to false on JDBC Connection”可以看出,Mybatis中的JDBC自动提交管理是false关闭的 ,需要我们手动提交。
public void test(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student = new Student();
student.setGender("男");
student.setName("大黑");
studentDao.insert(student);
sqlSession.commit();//提交数据库事务管理,告诉mysql所有的逻辑已经执行完了,你可以将所有sql语句执行了
sqlSession.close();
}
注意:只有在增删改查中需要手动提交事务管理。
当有需求是:须知道插入数据的id时(id为自增的)只需要在Mapper.xml文件的对应添加标签中声明几个属性就好
<!--
useGeneratedKeys:true 开启返回数据库中自动生成的主键的
keyColumn:主键列
keyProperty:属性是什么
添加这三个属性后,会将keyColumn的值封装到keyProperty属性中
-->
<insert id="insert" parameterType="Student" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
insert into student (name,gender) values (#{name},#{gender})
</insert>
<!--
注意:返回的主键并不是返回到方法的返回值,而是封装到student对象的id属性中
-->
#{}和${}的区别
#{}占位符
是经过预编译的编译好的SQL语句在取值,底层使用的是PreparedStatement对象,是安全的数据库访问#{}的方式可以有效地防止SQL注入。一般传值时使用。
${}拼接符
会传入参数字符串,取值后再去编译SQL语句,${}的方式无法防止SQL注入。一般用来动态传递列名。
Mybatis排序时使用order by 动态传参时用的是$ 而不是 #。
修改
- 在代理接口中添加方法;
int upDate(Student student);
- 在对应的Mapper.xml文件中添加SQL语句
<update id="upDate" parameterType="Student">
update student set name=#{name},gender=#{gender} where id = #{id}
</update>
- 测试
@Test
public void test2(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
Student student = new Student(5,"leukemia","女");
studentDao.upDate(student);
sqlSession.commit();
sqlSession.close();
}
删除
与之前一样
- 在代理接口中添加方法;
int Delete(int id);
- 在对应的Mapper.xml文件中添加SQL语句
<delete id="Delete" parameterType="int">
delete from student where id = #{id}
</delete>
- 测试
@Test
public void test3(){
SqlSession sqlSession = MybatisUtil.getSqlSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
studentDao.Delete(5);
sqlSession.commit();
sqlSession.close();
}
查询
我们当时在jdbc中查询到结果时需要循环,一个个手动的封装到对应属性当中
如:
while (resultSet.next()) {
Students student = new Students();
student.setId(resultSet.getInt("id"));
student.setNum(resultSet.getString("num"));
student.setName(resultSet.getString("name"));
student.setGender(resultSet.getString("gender"));
student.setPhone(resultSet.getString("phone"));
student.setGradeName(resultSet.getString("grade"));
student.setAdminName(resultSet.getString("account"));
student.setOpertime(resultSet.getTimestamp("oper_time"));
list.add(student);
}
使用Mybatis时就不需要在手动封装。
查询结果为一条数据时,可以实现将记录自动封装到对象中,实现方法有:
- 表中的列名与对象属性名完全一致;
- 开启mapUnderscoreToCamelCase 实现列名与方法名之间的转换。
当数据库表中列名含有下划线时,如:
student_phone CHAR(11)
可以在对应的实体类将属性严格按照驼峰命名
private String studentPhone;
并且在mybatisConfig.xml配置文件中进行一个setting全局配置
<!-- 从经典的数据库命名方式转为java的驼峰命名 user_ name==>userName -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
- 单张表中可以在SQL语句中定义别名,别名与属性名相同也可以封装到对象中。
select name,gender six,student_phone from student where id = #{id}
- 特殊情况,单独处理
<!--
resultMap标签中 id:map标识 type:表示返回值的数据类型
在resultMap标签里面我们需要做的是将列名和属性名对应上
单张表时只需要用在名称不一样的列中,相同的会自动映射
-->
<resultMap id="findStudentMap" type="Student">
<!--用来定义列名和属性名之间的关系:将gender列封装在six属性中-->
<result column="gender" property="six"></result>
</resultMap>
<select id="findStudentById" resultMap="findStudentMap">
select name,gender,student_phone from student where id = #{id}
</select>
查询结果为多条结果时
查询结果为多条数据时,非常简单,只需要将代理接口中的方法的返回值类型改为list集合就行
List<Student> findStudent();
多张表关联查询时
之前在jdbc中我们使用的是直接列所表示的意思当做一个私有属性,如:
在创建学生对象时,学生表中会有年级id,对应到具体的某一个年级,在jdbc中是创建私有属性
private String gradeName;
private int gradeid;
在Mybatis中只需要创建一个年级的私有属性就好
private Grade grade;
在对应的Mapper.xml文件中的写法如下:
<resultMap id="findStudentMap" type="student">
<!--id :主键映射 result:其他字段映射 association 嵌套结果映射 -->
<id column="id" property="id"></id>
<result column="gender" property="gender"></result>
<result column="name" property="name"></result>
<result column="student_phone" property="studentPhone"></result>
<!--javaType表示java中的类型是什么-->
<association property="grade" javaType="Grade">
<!--将gname 封装到Grade 的name属性中-->
<result column="gname" property="name"></result>
</association>
</resultMap>
<select id="findStudentById" resultMap="findStudentMap">
SELECT
s.id,
s.name,
s.gender,
s.student_phone,
g.name gname
FROM
student s
LEFT JOIN grade g
ON s.gradeid = g.id
WHERE s.id = #{id}
</select>
需要注意的是:
<result column="id" property="id"></result>
<result column="gender" property="gender"></result>
<result column="name" property="name"></result>
<result column="student_phone" property="studentPhone"></result>
按照之前所学习的内容,这些属性名与列名相匹配,可以不写,但是当有嵌套结果映射时,自动映射就停止了。
也是可以修改的。在配置文件中myBatisConfig.xml中
<!--是否自动映射-->
<setting name="autoMappingBehavior" value="FULL"/>
FULL:开启时,就会完全自动映射。当然也会存在问题,只要名字相同就会映射,如:在没有起别名的情况下,没有查询年级的id,但是Mybatis会自动将学生的id封装进年级的id中。
NONE:不自动映射;PARTIAL:(默认的)单张表自动映射,有嵌套关联时关闭自动映射;FULL:一直开启自动映射。
如果想查询学生集合时:
List<Student> findStudentList();
<select id="findStudentList" resultMap="findStudentMap">
SELECT
s.id,
s.name,
s.gender,
s.student_phone,
g.name gname
FROM
student s
LEFT JOIN grade g
ON s.gradeid = g.id
</select>
由以上代码知,在查询集合和查询单条数据都可以用同一条resultMap。
查询集合和查询单条数据的SQL语句大体相同,可以将SQL抽取出来:
<select id="findStudentList" resultMap="findStudentMap">
<include refid="selectStudent"></include>
</select>
<sql id="selectStudent">
SELECT
s.id,
s.name,
s.gender,
s.student_phone,
g.name gname
FROM
student s
LEFT JOIN grade g
ON s.gradeid = g.id
</sql>
一对多查询
例如:一个年级有很多学生,现在需要查询出某个年级的所有学生。
//年级实现类
public class Grade {
private Integer id;
private String name;
private Set<Student> students = new HashSet<>();
}
对应Mapper.xml文件中:
<resultMap id="findGradeStudentMap" type="Grade">
<id column="gid" property="id"/>
<result column="gname" property="name"/>
<collection property="students" javaType="java.util.HashSet" ofType="Student">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="gender" property="gender"/>
</collection>
</resultMap>
<select id="findGradeStudent" resultMap="findGradeStudentMap">
SELECT
s.id,
s.name,
s.gender,
g.id gid,
g.name gname
FROM
grade g
LEFT JOIN student s
ON s.gradeid = g.id
</select>
嵌套查询
将一个多表关联查询拆分为多次查询,先查询主表数据,然后查询关联表数据。
先查出年级,通过年级在查学生。
<resultMap id="findGradeStudentMap2" type="Grade">
<id column="id" property="id"/>
<result column="name" property="name"/>
<collection property="students" javaType="list" ofType="Student" select="findStudent" column="id">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="gender" property="gender"/>
</collection>
</resultMap>
<select id="findStudent" resultType="Student">
select id,name,gender from student where gradeid=#{id}
</select>
<select id="findGradeStudent2" resultMap="findGradeStudentMap2">
SELECT
g.id ,
g.name
FROM
grade g
</select>
(1). select:指定关联查询对象的 Mapper Statement ID 为 findStudent
(2). column=“id”:关联查询时将 id列的值传入 findStudent,并将 findStudent查询的结果映射到 Grade的 students属性中
(3).collection 和 association 都需要配置 select 和 column 属性,两者配置方法相同
注解方式
@Insert : 插入 sql , 和 xml insert sql 语法完全一样
如:
@Insert("insert into grade (name) value (#{name})")
void insert(String name);
@Select : 查询 sql, 和 xml select sql 语法完全一样
@Update : 更新 sql, 和 xml update sql 语法完全一样
@Delete : 删除 sql, 和 xml delete sql 语法完全一样
@Param : 入参
@Results : 设置结果集合
@Result : 结果