SQL映射文件
内容为雷丰阳老师的SSM框架内容记录
1.增删改标签
<insert id="insertEmployee" databaseId="">
INSERT INTO mybatis_0325.t_employee(empname, gender, email)
VALUE(#{empName}, #{gender}, #{email})
</insert>
实现获取到插入数据后的自增id:
<!--
让MyBatis将自动增长的id赋值给传入的employee对象的id属性
useGeneratedKeys="true":告诉mybatis我要使用sql中的自动增长;原生jdbc获取自增主键的方法
keyProperty="":告诉mybatis我要将获得到的自动增长的值赋给谁
-->
<insert id="insertEmployee" useGeneratedKeys="true" keyProperty="id">
INSERT INTO mybatis_0325.t_employee(empname, gender, email)
VALUE(#{empName}, #{gender}, #{email})
</insert>
对于一些不能使用自增长的数据库:
<!-- 在对于不能使用自增属性的数据库的时候可以这样 -->
<insert id="insertEmployee2">
<!-- 查询主键
order="BEFORE":before就是在核心sql语句执行前先进行查询 after就是之后再执行
在核心sql语句执行之一个sql先查到id;将查到的id赋给JavaBean的哪一个属性
selectKey order="BEFORE" resultType="integer" keyProperty="id"
再核心sql执行之前我创建一个integer类型的id来存增长的id
-->
<selectKey order="BEFORE" resultType="integer" keyProperty="id">
select max(id)+1 from t_employee
</selectKey>
INSERT INTO mybatis_0325.t_employee(id,empname, gender, email)
VALUE(#{id}, #{empName}, #{gender}, #{email})
</insert>
2.查标签
<!--
查询传参到底能传那些
-->
<!-- public Employee getEmpById(Integer id); -->
<select id="getEmpById" resultType="com.neu.bean.Employee">
select * from t_employee where id = #{id}
</select>
<!-- public Employee getEmpByIdAndName(Integer id, String empName); -->
<!--
select * from t_employee where id = #{id} and empname = #{empName}
Caused by: BindingException:
Parameter 'id' not found. Available parameters are [0, 1, param1, param2]
-->
<select id="getEmpByIdAndName" resultType="com.neu.bean.Employee">
<!-- select * from t_employee where id = #{param1} and empname = #{param2} -->
select * from t_employee where id = #{id} and empname = #{empName}
</select>
<!-- public Employee getEmployeeByIdAndName(Map<String, Object> map); -->
<select id="getEmployeeByIdAndName" resultType="com.neu.bean.Employee">
select * from t_employee where id = #{id} and empname = #{empName}
</select>
现象:
1)单个参数:
基本类型:
取值:#{随便写}
传入pojo
2)多个参数:
1. public Employee getEmpByIdAndName(Integer id, String empName)
取值:#{参数名}无效了;
可用:0,1(参数的索引)或者param1,param2(第几个参数paramN)
原因:只要传入了多个参数;mybatis会自动地将这些参数封装在一个map中;
而封装使用的key就是参数的索引和参数的第几个标识
Map<String, Object> map = new HashMap<>();
map.put("1",传入的值); map.put("2",传入的值);
#{key}就是从这个map中取值;
2. @Param(""):为参数指定key;命名参数,我们以后也推荐这么做
我们可以告诉mybatis,封装参数map的时候别乱来,我们可以指定key
public Employee getEmpByIdAndName(@Param("id")Integer id, @Param("empName")String empName);
3)传入了map:将多个要使用的参数封装起来
取值:#{key}
EmployeeDao:
public Employee getEmployeeByIdAndName(Map<String, Object> map);
MyBatisTest:
Map<String, Object> map = new HashMap<String, Object>();
map.put("id", 1);
map.put("empName", "admin");
Employee mapEmployee = employeeDao.getEmployeeByIdAndName(map);
4)传入了pojo(JavaBean):
取值:#{pojo的属性名}
参数内传入的是Employee对象
Employee getEmpByIdAndLastName(Employee emp);
select * from t_employee where id = #{id} and empname = #{empName}
多个参数:自动封装map
method01(@Param("id")Integer id, String empName, Employee employee);
Integer id -> #{id}
String empName -> #{param2}
Employee employee(取出这个对象里面的email) -> #{param3.email}
无论传入什么参数都要能正确的取值:
#{key/属性名}
①#{key}取值得时候可以设置一些规则;
#{id, jdbcType=INEGER};
javaType(java类型), jdbcType(jdbc类型), mode(数据库存储过程), numericScale(保留几位小数点), resultMap(结果集), typeHandler, jdbcTypeName,expression
只有jdbcType才可能是需要被指定的;
默认不指定jdbcType;mysql没问题;oracle没问题
万一传入的数据时null;mysql没问题,【oracle没办法了,他不知道是什么类型】
实际上mybatis中,两种取值方式:
#{属性名}:是参数预编译的方式,参数的位置都是用?替代,参数后来都是预编译设置进去的;安全,不会出现sql注入问题
${属性名}:不是参数预编译,而是直接和sql语句进行拼串;不安全
//id=1 or 1 = 1 or and empname=
传入一个'1 or 1 = 1 or'
有:sql语句只有此参数位置是支持预编译的
log_2017_12、log_2018_1;
select * from log_2018_1 where id = ? and empname = ?
例子:
map.put("tableName", "t_employee");
select * from ${tableName} where id = #{id} and empname = #{empName}
一般都是使用#{};安全
在不在支持参数预编译的位置要进行取值就只用${};
id = #{id} and empname = #{empName}:
select * from t_employee where id = ? and empname = ?
id = ${id} and empname = #{empName}:
select * from t_employee where id = 1 and empname = ?
查询方法内部是list集合:
sql映射文件:
<!-- public List<Employee> getAllEmps(); -->
<!-- resultType:如果返回的是集合,那么就写集合里面元素的类型 -->
<select id="getAllEmps" resultType="com.neu.bean.Employee">
select * from t_employee
</select>
测试文件:
@Test
public void test03() {
SqlSession openSession = sqlSessionFactory.openSession();
try{
EmployeeDao employeeDao = openSession.getMapper(EmployeeDao.class);
List<Employee> list = employeeDao.getAllEmps();
for(Employee emp : list){
System.out.println(emp);
}
}finally{
openSession.close();
}
}
查询方法返回到map集合:
查询单个放到map中:
dao类:
/**
* id empname gender email login_account
* 1 admin 0 admin@qq.com a
* @param id
* @return
*
* 列名作为key,值作为value
*/
public Map<String, Object> getEmpByIdReturnMap(Integer id);
xml文件:
<!-- 查询返回一个map -->
<!-- public Map<String, Object> getEmpByIdReturnMap(Integer id); -->
<select id="getEmpByIdReturnMap" resultType="map">
select * from t_employee where id = #{id}
</select>
测试类:
// 查询单条封装map
// Map<String, Object> map = employeeDao.getEmpByIdReturnMap(1);
// System.out.println(map);
查询多个方到map中
dao类:
/**
* key就是这个记录的主键
* value就是这条记录封装好的对象
* @return
*
* @MapKey("id")
* 把查处的记录的id得值作为key封装这个map
*/
@MapKey("id")
public Map<Integer, Employee> getAllEmpByIdReturnMap();
xml文件:
<!-- 查询多个返回一个map,查询多个的情况下,集合里面写元素的类型 -->
<!-- public Map<Integer, Employee> getAllEmpByIdReturnMap(); -->
<select id="getAllEmpByIdReturnMap" resultType="com.neu.bean.Employee">
select * from t_employee
</select>
测试类:
//查询多条记录封装map
Map<Integer, Employee> map = employeeDao.getAllEmpByIdReturnMap();
System.out.println(map);
Employee employee = map.get(1);
Integer id = employee.getId();
System.out.println(id);
resultMap自定义封装规则
sql映射文件:
<mapper namespace="com.neu.dao.CatDao">
<!-- public Cat getCatById(Integer id);
resultType="com.neu.bean.Cat":使用默认规则;属性列名一一对应
resultMap="mycat":查出数据封装结果的时候,使用mycat自定义规则
-->
<select id="getCatById" resultMap="mycat" >
<!-- select id, cname name, cAge age, cgender gender from t_cat where id = #{id} -->
select * from t_cat where id = #{id}
</select>
<!--
自定义结果集(resultMap):自己定义每一列数据和JavaBean得映射规则
type="":指定为哪个JavaBean自定义封装规则
id="":唯一标识;让别名在后面引用
id cName cAge cgender
1 加菲猫 12 0
-->
<resultMap type="com.neu.bean.Cat" id="mycat">
<!--
id:指定主键列的对应规则
column:指定哪一个是主键列
property:指定cat得哪个属性封装id这一列数据
-->
<id property="id" column="id"/>
<!-- 普通列 -->
<result property="name" column="cName"/>
<result property="age" column="cAge"/>
<result property="gender" column="cgender"/>
</resultMap>
</mapper>
Test测试文件:
/**
* 默认mybatis自动封装结果集
* 1.按照列名和属性名一一对应(不区分大小写);
* 2.如果不一一对应:
* 1.开启驼峰命名法(满足驼峰命名规则 aaa_bbb aaaBbb)
* 2.起别名
*/
@Test
public void test04() {
SqlSession openSession = sqlSessionFactory.openSession();
try{
CatDao catDao = openSession.getMapper(CatDao.class);
Cat cat = catDao.getCatById(1);
System.out.println(cat);
}finally{
openSession.close();
}
}
级联属性的方式查询出数据:
(当前类中有一个属性是引用外部类的)
public class Key{
private Integer id; //钥匙id
private String keyName; //钥匙名
private Lock lock; //当前钥匙能开哪个锁
}
public class Lock {
private Integer id; //锁id
private String lockName; //锁名
}
xml文件:
<mapper namespace="com.neu.dao.KeyDao">
<!--
private Integer id; //钥匙id
private String keyName; //钥匙名
private Lock lock; //当前钥匙能开哪个锁
id keyname lockid lid lockName
-->
<!-- public Key getKeyById(Integer id); -->
<select id="getKeyById" resultMap="myKey">
SELECT k.id, k.keyName, k.lockId, l.id lid, l.lockName FROM t_key k
LEFT JOIN t_lock l
ON k.lockId = l.id
WHERE k.id = #{id}
</select>
<!-- 自定义封装规则:使用级联属性封装出联合查询出的结果 -->
<!-- <resultMap type="com.neu.bean.Key" id="myKey">
<id property="id" column="id"/>
<result property="keyName" column="keyname"/>
<result property="lock.id" column="lid"/>
<result property="lock.lockName" column="lockName"/>
</resultMap> -->
<!-- mybatis推荐的<association property=""></association> -->
<resultMap type="com.neu.bean.Key" id="myKey">
<id property="id" column="id"/>
<result property="keyName" column="keyname"/>
<!-- 接下来的属性是一个对象,自定义这个对象得封装规则;使用association;表示联合了一个对象 -->
<!-- javaType:指定这个属性得类型 -->
<!-- property:写的是JavaBean里的属性; column:写的是你对应数据库要查的字段 -->
<association property="lock" javaType="com.neu.bean.Lock">
<!-- 定义lock属性对应的这个Lock对象如何封装 -->
<id property="id" column="lid"/>
<result property="lockName" column="lockName"/>
</association>
</resultMap>
</mapper>
Test类:
/**
* 联合查询情况下
* 1.使用级联属性封装联合查询后的所有结果
*/
@Test
public void test05() {
SqlSession openSession = sqlSessionFactory.openSession();
try{
KeyDao keyDao = openSession.getMapper(KeyDao.class);
Key key = keyDao.getKeyById(2);
System.out.println(key);
}finally{
openSession.close();
}
}
(当前类中有一个属性是List集合,List集合的类型是外部类)
public class Lock {
private Integer id; //锁id
private String lockName; //锁名
//查询锁子的时候把所有的钥匙也查出来
private List<Key> keys;
//1-1关联;1-多关联;多-多关联
//一个key开一把lock;
//从lock来看key;1-多
//从key表看lock:多-1
//多-多:
//student表 teacher表
//1-n; n-1; n-n ;外键应该放到那个表
//1-n:外键一定放在多的一端
//n-n:中间表存储对应关系
}
public class Key{
private Integer id; //钥匙id
private String keyName; //钥匙名
private Lock lock; //当前钥匙能开哪个锁
}
xml文件:
<mapper namespace="com.neu.dao.LockDao">
<!-- public Lock getLockById(Integer id); -->
<select id="getLockById" resultMap="myLock">
SELECT l.*, k.id kid, k.keyName FROM t_lock l
LEFT JOIN t_key k
ON l.id = k.lockId
WHERE l.id = #{id}
</select>
<resultMap type="com.neu.bean.Lock" id="myLock">
<id property="id" column="id"/>
<result property="lockName" column="lockName"/>
<!-- collection定义集合元素的封装
property:指定哪个属性是集合属性
javaType:指定对象类型(association)
ofType:指定集合元素的类型
-->
<collection property="keys" ofType="com.neu.bean.Key">
<!-- 标签体中,指定集合中这个元素的封装规则 -->
<id property="id" column="kid"/>
<result property="keyName" column="keyName"/>
</collection>
</resultMap>
</mapper>
Test文件:
@Test
public void test06() {
SqlSession openSession = sqlSessionFactory.openSession();
try{
LockDao lockDao = openSession.getMapper(LockDao.class);
Lock lock = lockDao.getLockById(3);
System.out.println(lock);
List<Key> keys = lock.getKeys();
for(Key all : keys){
System.out.println("Lock下的所有锁子" + all);
}
}finally{
openSession.close();
}
}
(分布查询)
KeyDao.xml
<!-- public Key getKeyByIdSimple(Integer id); -->
<select id="getKeyByIdSimple" resultMap="myKey02">
select * from t_key where id = #{id}
</select>
<resultMap type="com.neu.bean.Key" id="myKey02">
<id property="id" column="id"/>
<result property="keyName" column="keyName"/>
<!--
告诉mybatis自己去调用一个查询查锁子
select="":指定一个查询sql的唯一表示;mybatis自动调用指定的sql,将查处的lock封装进来
public Lock getLockByIdSimple(Integer id);需要传入锁子id
告诉mybatis把那一列的值传递过去
column:指定将哪一个数据传递过去
-->
<association property="lock"
select="com.neu.dao.LockDa.getLockByIdSimple"
column="lockid"></association>
</resultMap>
LockDao.xml
<!-- public Lock getLockByIdSimple(Integer id); -->
<select id="getLockByIdSimple" resultType="com.neu.bean.Lock">
select * from t_lock where id = #{id}
</select>
Test类
/**
* 分步查询:
* 0)、查询要是的时候顺便查出锁子;
* 1)、Key key = keyDao.getKeyById(1);
* 2)、Lock lock = lockDao.getLockById(1);
*/
@Test
public void test07(){
SqlSession openSession = sqlSessionFactory.openSession();
try{
KeyDao keyDao = openSession.getMapper(KeyDao.class);
Key key = keyDao.getKeyByIdSimple(2);
System.out.println(key);
}finally{
openSession.close();
}
}
(分布加载中的按需加载和延迟加载)
两个sql映射文件中不变
@Test
public void test07() throws InterruptedException{
SqlSession openSession = sqlSessionFactory.openSession();
try{
KeyDao keyDao = openSession.getMapper(KeyDao.class);
Key key = keyDao.getKeyByIdSimple(1);
//严重性能
System.out.println(key);
//按需加载;需要的时候再去查询;全局开启按需加载策略
//延迟加载:不着急加载(查询对象)
//假设我现在查钥匙查完后她睡了,然后过一会他想起来了,起来查了
Thread.sleep(3000);
String lock = key.getLock().getLockName();
System.out.println(lock);
}finally{
openSession.close();
}
}
mybatis—config.xml多一部分
<!-- 如果有多个列就是用
column="{id=id}"
key1 = 列名, key2 = 列名
-->
fetchType="lazy"全局加载懒加载
fetchType="eager"全局加载不懒加载
他只能写在collection和association标签里
<collection property="keys"
select="com.neu.dao.KeyDao.getKeysByLockId(Integer)"
column="id" fetchType="lazy"></collection>