5.1. 注解开发
采用注解开发可不用创建映射配置文件,直接在执行SQL语句的接口内使用注解即可。操作步骤如下:
在核心配置文件中引入接口类:
<mappers>
<!-- 接口类所在包 -->
<package name="com.itheima.mapper"/>
</mappers>
增删改查操作如下:
//直接在接口类中的增删改查方法上添加注解。格式即如下所示。
public interface StudentMapper {
@Select("SELECT * FROM student")
public abstract List<Student> selectAll();
@Insert("INSERT INTO student VALUES(#{id}, #{name}, #{age})")
public abstract Integer insert(Student stu);
@Update("UPDATE student SET age = #{age} WHERE id=#{id}")
public abstract Integer update(Student stu);
@Delete("DELETE FROM student WHERE id=#{id}")
public abstract Integer delete(Integer id);
}
//在测试类中
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);//加载mapper文件
Student stu = new Student(9,"生活呀",100);
//插入数据
Integer result = mapper.insert(stu);
System.out.println(result);
5.2. 多表模型操作:
5.2.1. 基本介绍:
一对一:在任意一方建立外键,关联对方主键;
一对多:在多的一方建立外键,关联一方主键;
多对多:借助中间表,中间表至少两个字段,分别关联两张表的主键;
5.2.2. 一对一
一对一通常涉及两张表,例如:银行卡 {id,number,pid} 与 持卡人p {id,name,age}。在查询时会涉及两张表。
创建映射配置文件:此时不能直接用<select>,而是需要如下的<resultMap>。
<mapper namespace="com.itheima.table01.OneToOneTest">
<!--配置字段和实体对象之间的映射关系-->
<!--id:唯一标识,type:所需赋值的对象名-->
<resultMap id="oneToOne" type="card">
<!--id标签:主键,column:SQL查询的列名,property:对象的属性名-->
<id column="cid" property="id"/>
<!--result标签:非主键,SQL其他查询列-->
<result column="number" property="number"/>
<!--association:card下包含的其他对象,也要依次赋值,javaType:被包含对象的数据类型。-->
<association property="p" javaType="person">
<id column="pid" property="id"/>
<result column="NAME" property="name"/>
<result column="age" property="age"/>
</association>
</resultMap>
<!-- SQL语句,查询结果类型通过resultMap赋值给对象的各个属性 -->
<select id="selectAll" resultMap="oneToOne">
SELECT c.id cid, number, pid, NAME, age FROM card c, person p WHERE c.pid = p.id
</select>
</mapper>
5.2.3. 一对多
具体步骤可参考上文,唯一区别是将<association>换为<collection>。
<resultMap id="OneToMany" type="classes">
<id column="cid" property="id"/>
<result column="cname" property="name"/>
<!-- collection:对象中包含List对象时,例如班级中包含多个学生。 -->
<collection property="students" ofType="student">
<id column="sid" property="id"/>
<result column="sname" property="name"/>
<result column="sage" property="age"/>
</collection>
</resultMap>
多对多处理方式可参考一对多。
5.2.4. 注解一对一
在核心配置文件中加载类包,如上所示。由于一对一涉及两张表,因此对每个表均要设置一个查询接口。
对于Person表的接口,创建的注释如下所示:
@Select("SELECT * FROM student WHERE id=#{id}")
public abstract Person selectById(Integer id);
对于Card表中的接口,由于其中包含Person属性,故创建注释如下:
@Select("SELECT * FROM card")
//属性是一个Result数组
@Results({
//对属性赋值
@Result(column = "id", property = "id"),
@Result(column = "number", property = "number"),
//通过外键查询Person值
@Result(property = "p", javaType = Person.class, column = "pid",
//one 特指一对一情况。其中select需要定位到具体方法名。且要求方法提供了查询注解,如上。
one = @One(select = "com.itheima.one_to_one.PersonMapper.selectById")
)
})
public abstract List<Card> selectAll();
5.2.5. 注解一对多
在核心配置文件中加载多个类时,可直接加载项目包:
<mappers>
<package name="com.itheima"/>
</mappers>
同样涉及多张表,对于被包含的对象也要单独设置一个注解查询接口,本案例中设计classes与student,classes包含List <student>。
//在StudentMapper中,设置查询接口
public interface StudentMapper {
@Select("SELECT * FROM student WHERE cid=#{cid}")
public abstract Student selectByCid(Integer cid);
}
在Classes中:
//在Classes接口中,使用many = @Many进行多对多查询。
public interface ClassesMapper {
@Select("SELECT * FROM classes")
@Results({
@Result(column = "id", property = "id"),
@Result(column = "name", property = "name"),
@Result(
property = "students", //包含的变量名
javaType = List.class, //变量所属类型
column = "id", //用班级表中的id,作为student表的查询条件。
many = @Many(select = "com.itheima.one_to_many.StudentMapper.selectByCid")
)
})
public abstract List<Classes> selectAll();
}
5.2.6. 注解多对多
多对多与一对多格式是一致的,只要搞清楚SQL语句的逻辑就可。
在本案例中学生表student和课程表course分别是多对多的关系,并通过中间表stu_cr关联。
在CourseMapper中:
public interface CourseMapper {
@Select("SELECT c.id, c.name FROM stu_cr sc, course c
WHERE sc.sid = #{id} AND sc.cid = c.id")
public abstract List<Course> selectById(Integer id);
}
在StudentMapper中:
public interface StudentMapper {
@Select("SELECT DISTINCT s.id, s.name, s.age FROM student s, stu_cr sc
WHERE sc.sid = s.id")
@Results({
@Result(column = "id", property = "id"),
@Result(column = "name", property = "name"),
@Result(column = "age", property = "age"),
@Result(
property = "courses",
javaType = List.class,
column = "id",
many = @Many(select = "com.itheima.many_to_many.CourseMapper.selectById")
)
})
public abstract List<Student> selectAll();
}
5.3. 构建SQL语句功能类
5.3.1. 单独创建SQL生成类
具体示例如下:
public class ReturnSql {
//查询类,返回查询SQL语句
public String getSelectAll(){
return new SQL(){{ SELECT("*"); FROM("student");}}.toString();
}
//插入类,返回插入SQL语句
public String getInsert(Student stu){
return new SQL(){{ INSERT_INTO("student");
INTO_VALUES("#{id}, #{name}, #{age}");}}.toString();
}
//更新类,返回更新SQL语句
public String getUpdate(Student stu){
return new SQL(){{UPDATE("student");
SET("age=#{age}");
WHERE("id=#{id}"); }}.toString();
}
//删除类,返回删除SQL语句
public String getDelete(Integer id){
return new SQL(){{DELETE_FROM("student");
WHERE("id = #{id}"); }}.toString();
}
}
5.3.2. 接口类
接口类注解开发需要使用全新注解形式:
public interface StudentMapper {
//需要使用带有Provider的注解进行开发。
//其中type=上述SQL生成类。method=SQL生成类中所使用的方法名。
@SelectProvider(type = ReturnSql.class, method = "getSelectAll")
public abstract List<Student> selectAll();
@InsertProvider(type = ReturnSql.class, method = "getInsert")
public abstract Integer insert(Student stu);
@UpdateProvider(type = ReturnSql.class, method = "getUpdate")
public abstract Integer update(Student stu);
@DeleteProvider(type = ReturnSql.class, method = "getDelete")
public abstract Integer delete(Integer id);
}