<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.properties"></properties>
<typeAliases>
<!--<typeAlias alias="user" type="com.kuang.bean.User"></typeAlias>-->
<package name="com.kuang.bean"></package>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="1114"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/kuang/dao/UserMapper.xml"/>
</mappers>
</configuration>
表示使用数据库连接
<properties resource="db.properties"></properties> 表示引入外部的配置文件
<typeAliases>
<!--<typeAlias alias="user" type="com.kuang.bean.User"></typeAlias>-->
<package name="com.kuang.bean"></package>
</typeAliases>
表示该类可以使用别名
mappers
作用:扫包,为mapper接口创建实现类
方式一
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
可以将mapper.xml放在dao或者resource包下
方式二
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Yv6asuB-1638366132989)(C:\Users\yyp\AppData\Roaming\Typora\typora-user-images\image-20211110145129894.png)]
<mappers>
<mapper class="com.kuang.dao.UserMapper"></mapper>
</mappers>
dao的命名要和mapper.xml的命名一致,并且放到一个包下面
方式三
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ktgAOSLf-1638366132992)(C:\Users\yyp\AppData\Roaming\Typora\typora-user-images\image-20211110145129894.png)]
<mappers>
<package name="com.kuang.dao"></package>
</mappers>
dao的命名要和mapper.xml的命名一致,并且放到一个包下面
<?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="com.kuang.dao.DeptMapper">
</mapper>
<settings>
<setting name="logImpl" value="LOG4J"/>
settings>
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssmbuild?useSSL=true&useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=1114
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p7cHMDp6-1638366132994)(C:\Users\yyp\AppData\Roaming\Typora\typora-user-images\image-20211110150909249.png)]
//id:表示对哪个resultMap作映射 type:表示返回值类型,可以从其中拿到属性
<resultMap id="UserMap" type="User">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<result column="pwd" property="password"></result>
</resultMap>
<select id="getUserById" resultMap="UserMap">
SELECT * from user where id = #{id}
</select>
标签:
id:是该resultMap的一个标志,可以被其他resultMap使用
type:表示返回类型
id:表示这是主键列,会有特殊的封装规则
result:表示这是普通列
column:对应表中的列名
property:表示javaBean中对应的属性名
说明:id 和 column就是表中列名或者列的别名
CREATE TABLE tbl_student(
id INT(10) PRIMARY KEY,
NAME VARCHAR(20)
);
CREATE TABLE tbl_stu_score(
math VARCHAR(10),
english VARCHAR(10),
stu_id INT(10),
CONSTRAINT fk_stu_score FOREIGN KEY(stu_id)
REFERENCES tbl_student(id)
);
INSERT INTO tbl_student VALUES(1,"张三"),
(0002,"李四");
INSERT INTO tbl_stu_score VALUES
(100,100,1),
(99,99,2)
INSERT INTO tbl_stu_score VALUES(98,98,3)
#报错,因为没有0003这个学号
DELETE FROM tbl_student WHERE id = 1
#报错,无法删除,因为学生成绩表中引用了学生表中的id字段
#正确的删除方式
#首先删除成绩表
DELETE FROM tbl_stu_score WHERE stu_id = 1
#再删除学生表
DELETE FROM tbl_student WHERE id = 1
ALTER TABLE tbl_emp add CONSTRAINT emp_dept_fk FOREIGN KEY (d_id)
REFERENCES tbl_dept(dept_id)
ALTER TABLE 子表 ADD CONSTRAINT 外键名 FOREIGN KEY (关联字段)
REFERENCES 主表(被关联的字段) on delete cascade on update restrict;
<resultMap id="getDifEmp" type="Employee">
<id column="id" property="id"></id>
<result column="last_name" property="lastName"></result>
<result column="gender" property="gender"></result>
<result column="email" property="email"></result>
<result column="d_id" property="dept.id"></result>
<result column="dept_name" property="dept.deptName"></result>
</resultMap>
<!--public Employee getEmployeeById(Integer id);-->
<select id="getEmployeeById" resultMap="getDifEmp">
SELECT e.`id`, e.`last_name`, e.`gender`, e.`email`, e.`d_id`,
d.`dept_name`
FROM tbl_employee e
INNER JOIN tbl_dept d ON e.`d_id` = d.`id`
WHERE e.id = #{id}
</select>
<resultMap id="getDifEmp2" type="Employee">
<id column="id" property="id"></id>
<result column="last_name" property="lastName"></result>
<result column="gender" property="gender"></result>
<result column="email" property="email"></result>
<association property="dept" javaType="Dept">
<id column="id" property="id"></id>
<result column="dept_name" property="deptName"></result>
</association>
</resultMap>
association:表示该bean中有联合了一个bean类型的属性,现在要自定义封装该联合对象
property:javaBean中联合的那个属性的属性名
javaType:该bean对应的类型
注意:我们使用联合查询的时候,要注意sql语句,同时要把联合的那个bean对象所在表的数据查询出来,这样才能有数据且成功赋值到这个bean所在的属性
<select id="queryAllEmps" resultMap="EmpAndDeptLimit"> SELECT e.emp_id,e.emp_name,e.gender,e.email,d.dept_id,d.dept_name FROM tbl_emp e LEFT JOIN tbl_dept d ON e.d_id = d.dept_id select>
要查询出Emp对象
Emp中含有d_id,它来自于Dept中;
第一步查询出Emp的信息,不管是否要查询出d_id来封装,都会查询到d_id;
第二步根据d_id来查询出对应的Dept对象;最后封装成一个Emp对象返回
<resultMap id="getStepEmp" type="Employee">
<id column="id" property="id"></id>
<result column="last_name" property="lastName"></result>
<result column="gender" property="gender"></result>
<result column="email" property="email"></result>
//第二步查询
<association property="dept" select="com.kuang.dao.DeptMapper.getDeptById" column="d_id"></association>
</resultMap>
//第一步查询
<!-- public Employee getEmpByStep(Integer id);-->
<select id="getEmpByStep" resultMap="getStepEmp">
SELECT * from tbl_employee where id = #{id}
</select>
property:表示联合的bean对象
select:当前property是调用select中指定的方法查询出来的
column:表示要将第一次查询出的哪个属性值传递到第二次select中的sql参数中
<settings>
<setting name="lazyLoadingEnabled" value="true"></setting>
<setting name="aggressiveLazyLoading" value="false"></setting>
</settings>
举例
@Test
public void testStep(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
Employee emp = mapper.getEmpByStep(6);
System.out.println(emp.getLastName());
sqlSession.close();
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pRZW8yEm-1638366132996)(C:\Users\yyp\AppData\Roaming\Typora\typora-user-images\image-20211111103938149.png)]
查询一个部门中所有的Emps
<resultMap id="getList" type="Dept">
<id column="id" property="id"></id>
<result column="dept_name" property="deptName"></result>
<collection property="emps" ofType="Employee">
<id column="id" property="id"></id>
<result column="last_name" property="lastName"></result>
<result column="gender" property="gender"></result>
<result column="email" property="email"></result>
</collection>
</resultMap>
<!--public Dept getDeptAndListById(Integer id);-->
<select id="getDeptAndListById" resultMap="getList">
SELECT d.`id`, d.`dept_name` ,
e.`id`, e.`last_name`, e.`gender`, e.`email`
FROM tbl_dept d
LEFT JOIN tbl_employee e ON d.`id` = e.`d_id`
WHERE d.`id` = #{id}
</select>
collection:表示联合的属性是一个集合
property:表示联合的属性名
ofType:表示联合的属性的类型
<resultMap id="getListStep" type="Dept">
<id column="id" property="id"></id>
<result column="dept_name" property="deptName"></result>
<collection property="emps" select="com.kuang.dao.EmployeeMapper.getEmployeeBydid" column="id"></collection>
</resultMap>
<!--public Dept getDeptAndListByStep(Integer id);-->
<select id="getDeptAndListByStep" resultMap="getListStep">
select * from tbl_dept where id = #{id};
</select>
<resultMap id="getListStep" type="Dept">
<id column="id" property="id"></id>
<result column="dept_name" property="deptName"></result>
<!--public List<Employee> getEmployeeBydid(Integer did);-->
<collection property="emps"
select="com.kuang.dao.EmployeeMapper.getEmployeeBydid"
column="{did = id}"></collection>
</resultMap>
<!--public Dept getDeptAndListByStep(Integer id);-->
<select id="getDeptAndListByStep" resultMap="getListStep">
select * from tbl_dept where id = #{id};
</select>
<resultMap id="getEmpDisc" type="Employee">
<id column="id" property="id"></id>
<result column="last_name" property="lastName"></result>
<result column="gender" property="gender"></result>
<result column="email" property="email"></result>
<discriminator javaType="string" column="gender">
<!--如果是女生-->
<case value="0" resultType="com.kuang.bean.Employee">
<association property="dept"
select="com.kuang.dao.DeptMapper.getDeptById"
column="d_id"></association>
</case>
<!--如果是男生-->
<case value="1" resultType="com.kuang.bean.Employee">
<id column="id" property="id"></id>
<result column="last_name" property="lastName"></result>
<result column="gender" property="gender"></result>
<result column="last_name" property="email"></result>
</case>
</discriminator>
</resultMap>
column:表示要判断的是哪一列
javaType:表示列值的类型
value:表示列值
resultType:表示将case包围的该对象返回给谁
可以降低数据库查询压力,将大量的查询,分成小部分来查询
<!-- public User getUserById(String id); -->
<select id="getUserById" resultMap="UserMap">
SELECT * from user where id = #{id2312312sdfsadf}
</select>
#{}直接传参数名会报错:Parameter ‘id’ not found. Available parameters are [arg1, arg0, param1, param2]
对于方法中传入多个参数的情况,参数都会被封装到一个map中,sql中可以通过#{key}的形式来取参数value; 相当于去map中取值
可以用param1…paramN来指定sql中待传入的参数,也可以用arg0,arg1来指定
key : param1…paramN arg0…argN
value : 方法中传入的值
例子
<!--public User getUserByTw(Integer id,String name);-->
<select id="getUserByTw" resultType="User">
SELECT * from user where id = #{arg0} and name = #{arg1}
</select>
key : @param(“ ”) 括号中的命名
value :方法中传入的值
方法:
public User getUserByTw(@Param("id") Integer id, @Param("name") String name);
xml配置:
<!--public User getUserByTw(@Param("id") Integer id, @Param("name") String name);-->
<select id="getUserByTw" resultType="User">
SELECT * from user where id = #{param1} and name = #{param2}
</select>
比如方法中形参是pojo/Map/Collection,其实这时候方法中传进来也是多个参数,但是在方法中又只体现传入一个值
此时的key就是直接对应于pojo/map中的key
举例
mapper
public User getUserByMap(Map<String,Object> map);
(mapper.xml)
<!-- public User getUserByMap(Map<String,Object> map);-->
<select id="getUserByMap" resultType="User">
SELECT * from #{tableName} where id = #{id} and name = #{name}
// #{key} 相当于去map中取值
</select>
(测试类)
@Test
public void testGetByMap() {
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String,Object> map = new HashMap<String, Object>();
map.put("id",1);
map.put("name","狂神");
map.put("tableName","user")
User userByMap = mapper.getUserByMap(map);
System.out.println(userByMap);
}
}
public User getUser(@Param("id") Integer id,@Param("user") User u);
取值:id ===> #{id} name ===> #{user.name}
②
对于传入Collection(List,Set)类型或者数组,也会把他们封装在map中
取值方式:
Collection ===> collection) ; 对于List还可以这样取List ===> list
数组 ===> array
举例:方法中传入List
public User getUser(List<User> users)
取值:取第一个值 #{list[0]}
#{}是采用预编译的方式,可以防止sql注入,只能取参数位置的值
${}是取出来的值直接拼接在sql语句中,会有sql注入问题
<!-- public User getUserById(String id); -->
<select id="getUserById" resultType="User">
SELECT * from user where id = ${id}
</select>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DW0AdOuI-1638366132998)(C:\Users\yyp\AppData\Roaming\Typora\typora-user-images\image-20211110204627536.png)]
select * from ${tableName} where id = #{id}
select * from user order by ${name}
可以实现sql的复用
根据不同的查询条件,使用同一个条sql语句,查询出不同的结果
<!--public List<Blog> getBlobIf(Map map);-->
<select id="getBlobIf" resultType="Blog">
SELECT * from mybatis.blog
<where>
<if test="title != null">
and title = #{title}
</if>
<if test="author != null">
and autore = #{author}
</if>
</where>
</select>
表示:where后面的语句如果有多余的and/or,会将其自动去除;如果where后面没有语句,则将where自动去除
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
trim标签这样使用效果和where的效果相同
<!--public List<Blog> getBlobSwitch(Map map);-->
<select id="getBlobChoose" resultType="Blog">
SELECT * from mybatis.blog
<where>
<choose>
<when test="title != null">
title = #{title}
</when>
<when test="author != null">
and author = #{author}
</when>
<otherwise>
views = #{views}
</otherwise>
</choose>
</where>
</select>
<!--public int updateBlob(Map map);-->
<update id="updateBlob">
UPDATE mybatis.blog
<set>
<if test="title != null">
title = #{title},
</if>
<if test="author != author">
author = #{author},
</if>
</set>
where id = #{id}
</update>
:会自动去掉set后面的逗号
<trim prefix="SET" suffixOverrides=",">
...
<trim>
trim在这里使用的效果和set相同
<sql id="if-title-author">
<if test="title != null">
and title = #{title}
</if>
<if test="author != null">
and autore = #{author}
</if>
</sql>
<!--select * from mybatis.blog where (id = 1 or id=2 or id=3 );-->
<!--public List<Blog> getBlobForEach(Map map);-->
<select id="getBlobForEach" resultType="Blog">
SELECT * from mybatis.blog
<where>
<foreach collection="ids" item="id" index="index"
open="(" separator="or" close=")">
id = #{id}
</foreach>
</where>
</select>
collection:表示map中的一个元素(在这里是一个集合)
item:表示集合中的每一项元素
如果不是最后一项,会使用separator="or"进行拼接,否则使用close结束
存在内存中的临时数据
数据库的查询会占用资源,需要使用缓存来解决这个问题
默认情况,只有一级缓存开启,就是在一个sqlSession中
二级缓存是需要手动开启,它可以在一个namespace(mapper接口)方法中有效
在同一个sqlSession中有效
一级缓存默认开启,无法关闭
失效的几种情况
<settings>
<setting name="cacheEnabled" value="true">setting>
settings>
在xml中开启二级缓存
<cache/>
在对应的mapper中开启二级缓存
<build>
<resources>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>falsefiltering>
resource>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>falsefiltering>
resource>
resources>
build>