目录
向sql语句传参
1.mybatis日志输出配置
注意:标签按顺序书写
mybatis开启日志:使用settings标签
<settings>
<!-- SLF4J 选择slf4j输出! -->
<setting name="logImpl" value="SLF4J"/>
</settings>
2.#{}形式
在MyBatis中,会将sql语句中的#{}置换成问号占位符
3.${}形式
${}形式传参,底层MyBatis做的是字符串拼接操作
结论:实际开发中,能用#{}实现的,肯定不用${}。
特殊情况: 动态的不是值,是列名或者关键字,需要使用${}拼接
//注解方式传入参数!!
@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column,
@Param("value") String value);
数据输入
1.单个简单类型参数
随意命名(但一般还是和接口方法参数名相同)
int deleteById(Integer id);
<!-- 场景 1:传入的单个简单类型 key随便写,一般情况下推荐使用参数名!!!-->
<delete id="deleteById">
delete from t_emp where emp_id = #{hahhhhh}
</delete>
2.实体类类型参数
一般和实体类属性名相同
int insertEmp(Employee employee);
<!-- 场景 2:传入的是一个实体对象,key如何写? ==》 key = 属性名 即可 -->
<insert id="insertEmp">
insert into t_emp(emp_name,emp_salary) values(#{empName},#{empSalary})
</insert>
对应关系
结论
Mybatis会根据#{}中传入的数据,加工成getXxx()方法,通过反射在实体类对象中调用这个方法,从而获取到对应的数据。填充到#{}解析后的问号占位符这个位置。
3.多个简单类型参数
使用注解@Param("别名")
List<Employee> queryByNameAndSalary(@Param("nam") String name, @Param("sal") Double salary);
<!--
场景 3:传入多个简单类型,key如何写?
可不可以随便写?不可以
按照形参名称获取?也不可以
方案1:使用注解@Param("abc") ===> #{abc} 【推荐】
方案2:mybatis默认机制,从左到右一次arg0,arg1;或者从左到右依次param1,param2;例如#{arg0}
可混用!
-->
<select id="queryByNameAndSalary" resultType="com.atguigu.pojo.Employee">
select emp_id empId,emp_name empName,emp_salary empSalary
from t_emp where emp_name = #{nam} and emp_salary = #{sal}
<!-- select emp_id empId,emp_name empName,emp_salary empSalary-->
<!-- from t_emp where emp_name = #{arg0} and emp_salary = #{arg1}-->
<!-- select emp_id empId,emp_name empName,emp_salary empSalary-->
<!-- from t_emp where emp_name = #{param1} and emp_salary = #{param2}-->
<!-- select emp_id empId,emp_name empName,emp_salary empSalary-->
<!-- from t_emp where emp_name = #{param1} and emp_salary = #{param2}-->
<!-- select emp_id empId,emp_name empName,emp_salary empSalary-->
<!-- from t_emp where emp_name = #{param1} and emp_salary = #{sal}-->
</select>
对应关系
4.Map类型参数
int insertEmpMap(Map<String,Object> map);
<!--
场景 4:传入map 如何指定key的值?
key = map的key值即可
-->
<insert id="insertEmpMap">
insert into t_emp(emp_name,emp_salary) values(#{name},#{salary})
</insert>
junit测试
private SqlSession session;
//junit5会在每一个@Test方法前执行@BeforeEach方法
@BeforeEach
public void init() throws IOException {
session = new SqlSessionFactoryBuilder()
.build(
Resources.getResourceAsStream("mybatis-config.xml"))
.openSession();
}
@Test
public void testUpdateEmpNameByMap() {
EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("empSalaryKey", 999.99);
paramMap.put("empIdKey", 5);
int result = mapper.updateEmployeeByMap(paramMap);
log.info("result = " + result);
}
//junit5会在每一个@Test方法后执行@@AfterEach方法
@AfterEach
public void clear() {
session.commit();
session.close();
}
对应关系
#{}对应Map中的key
使用场景
有很多零散的参数需要传递,但是没有对应的实体类类型可以使用。使用@Param注解一个一个传入又太麻烦了。所以都封装到Map中。
数据输出
1.返回单个简单类型
int selectEmpCount();
<select id="selectEmpCount" resultType="int">
select count(*) from t_emp
</select>
细节解释:
- select标签,通过resultType指定查询返回值类型!
- resultType = "全限定符 | 别名 | 如果是返回集合类型,写范型类型即可"
别名问题:
下面是Mybatis为常见的 Java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。
自定义别名设置:
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
</typeAliases>
当这样配置时,`Blog` 可以用在任何使用 `domain.blog.Blog` 的地方。
也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
<typeAliases> <package name="domain.blog"/> </typeAliases>
每一个在包 `domain.blog` 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 `domain.blog.Author` 的别名为 `author`;若有注解,则别名为其注解值。见下面的例子:
@Alias("author")
public class Author {
...
}
2.返回实体类对象
<!-- 编写具体的SQL语句,使用id属性唯一的标记一条SQL语句 -->
<!-- resultType属性:指定封装查询结果的Java实体类的全类名 -->
<select id="selectEmployee" resultType="com.atguigu.mybatis.entity.Employee">
<!-- Mybatis负责把SQL语句中的#{}部分替换成“?”占位符 -->
<!-- 给每一个字段设置一个别名,让别名和Java实体类中属性名一致 -->
select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_id=#{maomi}
</select>
通过给数据库表字段加别名,让查询结果的每一列都和Java实体类中属性对应起来。
增加全局配置自动识别对应关系
在 Mybatis 全局配置文件中,做了下面的配置,select语句中可以不给字段设置别名
<!-- 在全局范围内对Mybatis进行配置 -->
<settings>
<!-- 具体配置 -->
<!-- 从org.apache.ibatis.session.Configuration类中可以查看能使用的配置项 -->
<!-- 将mapUnderscoreToCamelCase属性配置为true,表示开启自动映射驼峰式命名规则 -->
<!-- 规则要求数据库表字段命名方式:单词_单词 -->
<!-- 规则要求Java实体类属性名命名方式:首字母小写的驼峰式命名 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
3.返回Map类型
<!-- Map<String,Object> selectEmpNameAndMaxSalary(); -->
<!-- 返回工资最高的员工的姓名和他的工资 -->
<select id="selectEmpNameAndMaxSalary" resultType="map">
SELECT
emp_name 员工姓名,
emp_salary 员工工资,
(SELECT AVG(emp_salary) FROM t_emp) 部门平均工资
FROM t_emp WHERE emp_salary=(
SELECT MAX(emp_salary) FROM t_emp
)
</select>
4.返回List类型
resultType填相对应的泛型类型。
查询结果返回多个实体类对象,希望把多个实体类对象放在List集合中返回。此时不需要任何特殊处理,在resultType属性中还是设置实体类类型即可。
<!-- List<Employee> selectAll(); -->
<select id="selectAll" resultType="com.atguigu.mybatis.entity.Employee">
select emp_id empId,emp_name empName,emp_salary empSalary
from t_emp
</select>
4.返回主键值
1)自增长类型主键
<!-- int insertEmployee(Employee employee); -->
<!-- useGeneratedKeys属性字面意思就是“使用生成的主键” -->
<!-- keyProperty属性可以指定主键在实体类对象中对应的属性名,Mybatis会将拿到的主键值存入这个属性 -->
<insert id="insertEmployee" useGeneratedKeys="true" keyProperty="empId">
insert into t_emp(emp_name,emp_salary)
values(#{empName},#{empSalary})
</insert>
注意
Mybatis是将自增主键的值设置到实体类对象中,而不是以Mapper接口方法返回值的形式返回。
2)非自增长类型主键
而对于不支持自增型主键的数据库(例如 Oracle)或者字符串类型主键,则可以使用 selectKey 子元素:selectKey 元素将会首先运行,id 会被设置,然后插入语句会被调用!
使用 `selectKey` 帮助插入UUID作为字符串类型主键示例:
<insert id="insertUser" parameterType="User">
<selectKey keyProperty="id" resultType="java.lang.String"
order="BEFORE">
SELECT UUID() as id
</selectKey>
INSERT INTO user (id, username, password)
VALUES (
#{id},
#{username},
#{password}
)
</insert>
5.实体类属性和数据库字段对应关系
1)全局配置自动识别驼峰式命名规则
<!-- 使用settings对Mybatis全局进行设置 -->
<settings>
<!-- 将xxx_xxx这样的列名自动映射到xxXxx这样驼峰式命名的属性名 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
2)使用resultMap
<!--
列名和属性名不一致如何解决:
1.起别名 select t_id tId,t_name tName from teacher where t_id = #{id}
2.开启驼峰式映射 <setting name="mapUnderscoreToCamelCase" value="true"/>
3.resultMap自定义映射(resultType和resultMap二选一)
resultType按照规则自动映射,按照是否开启驼峰式映射,自己映射属性和列名,只能映射一层结构!
深层次的对象结构无法映射,多表查询的时候结果无法映射!
resultMap标签,自定义映射关系,可以深层次,可以单层次!!!
-->
<!--
声明resultMap标签,自己定义映射规则
id标识 -> select resultMap="标识"
type -> 具体的返回值类型
<id 主键映射关系
<property 普通列的映射关系
-->
<resultMap id="tMap" type="teacher">
<id column="t_id" property="tId"/>
<result column="t_name" property="tName"/>
</resultMap>
<select id="queryById" resultMap="tMap">
select * from teacher where t_id = #{id}
<!-- select t_id tId,t_name tName from teacher where t_id = #{id}-->
</select>
<!-- 专门声明一个resultMap设定column到property之间的对应关系 -->
<resultMap id="selectEmployeeByRMResultMap" type="com.atguigu.mybatis.entity.Employee">
<!-- 使用id标签设置主键列和主键属性之间的对应关系 -->
<!-- column属性用于指定字段名;property属性用于指定Java实体类属性名 -->
<id column="emp_id" property="empId"/>
<!-- 使用result标签设置普通字段和Java实体类属性之间的关系 -->
<result column="emp_name" property="empName"/>
<result column="emp_salary" property="empSalary"/>
</resultMap>
<!-- Employee selectEmployeeByRM(Integer empId); -->
<select id="selectEmployeeByRM" resultMap="selectEmployeeByRMResultMap">
select emp_id,emp_name,emp_salary from t_emp where emp_id=#{empId}
</select>