mybatis配置文件设计标签和顶层结构如下:
configuration(配置)
我们可以在mybatis的配置文件使用settings标签设置,输出运过程SQL日志!
通过查看日志,我们可以判定#{} 和 ${}的输出效果!
settings设置项:
日志配置:
<settings>
<setting name="logImpl" value="SLF4J"/>
settings>
//注解方式传入参数!!
@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column,
@Param("value") String value);
这里数据输入具体是指上层方法(例如Service方法)调用Mapper接口时,数据传入的形式。
简单类型:只包含一个值的数据类型
复杂类型:包含多个值的数据类型
Employee selectEmployee(Integer empId);
<select id="selectEmployee" resultType="com.alex.mybatis.entity.Employee">
select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_id=#{empId}
select>
单个简单类型参数,在#{}中可以随意命名,但是没有必要。通常还是使用和接口方法参数同名。
int insertEmployee(Employee employee);
<insert id="insertEmployee">
insert into t_emp(emp_name,emp_salary) values(#{empName},#{empSalary})
insert>
int updateEmployee(@Param("empId") Integer empId,@Param("empSalary") Double empSalary);
<update id="updateEmployee">
update t_emp set emp_salary=#{empSalary} where emp_id=#{empId}
update>
int updateEmployeeByMap(Map<String, Object> paramMap);
<update id="updateEmployeeByMap">
update t_emp set emp_salary=#{empSalaryKey} where emp_id=#{empIdKey}
update>
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();
}
对应关系
使用场景
数据输出总体上有两种形式:
我们需要做的是,指定查询的输出数据类型即可!
并且插入场景下,实现主键数据回显示!
int selectEmpCount();
<select id="selectEmpCount" resultType="int">
select count(*) from t_emp
select>
Mybatis 内部给常用的数据类型设定了很多别名。 以 int 类型为例,可以写的名称有:int、integer、Integer、java.lang.Integer、Int、INT、INTEGER 等等。
@Test
public void testEmpCount() {
EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);
int count = employeeMapper.selectEmpCount();
log.info("count = " + count);
}
细节解释:
select标签,通过resultType指定查询返回值类型!
resultType = “全限定符 | 别名 | 如果是返回集合类型,写范型类型即可”
别名问题:
<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 {
...
}
下面是Mybatis为常见的 Java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。
别名 | 映射的类型 |
---|---|
_byte | byte |
_char (since 3.5.10) | char |
_character (since 3.5.10) | char |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
char (since 3.5.10) | Character |
character (since 3.5.10) | Character |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
biginteger | BigInteger |
object | Object |
object[] | Object[] |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
Employee selectEmployee(Integer empId);
<select id="selectEmployee" resultType="com.alex.mybatis.entity.Employee">
select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_id=#{maomi}
select>
通过给数据库表字段加别名,让查询结果的每一列都和Java实体类中属性对应起来。
增加全局配置自动识别对应关系
在 Mybatis 全局配置文件中,做了下面的配置,select语句中可以不给字段设置别名
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
settings>
适用于SQL查询返回的各个字段综合起来并不和任何一个现有的实体类对应,没法封装到实体类对象中。能够封装成实体类类型的,就不使用Map类型。
Mapper接口的抽象方法
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>
@Test
public void testQueryEmpNameAndSalary() {
EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);
Map<String, Object> resultMap = employeeMapper.selectEmpNameAndMaxSalary();
Set<Map.Entry<String, Object>> entrySet = resultMap.entrySet();
for (Map.Entry<String, Object> entry : entrySet) {
String key = entry.getKey();
Object value = entry.getValue();
log.info(key + "=" + value);
}
}
查询结果返回多个实体类对象,希望把多个实体类对象放在List集合中返回。此时不需要任何特殊处理,在resultType属性中还是设置实体类类型即可。
Mapper接口中抽象方法
List<Employee> selectAll();
<select id="selectAll" resultType="com.alex.mybatis.entity.Employee">
select emp_id empId,emp_name empName,emp_salary empSalary
from t_emp
select>
@Test
public void testSelectAll() {
EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);
List<Employee> employeeList = employeeMapper.selectAll();
for (Employee employee : employeeList) {
log.info("employee = " + employee);
}
}
int insertEmployee(Employee employee);
<insert id="insertEmployee" useGeneratedKeys="true" keyProperty="empId">
insert into t_emp(emp_name,emp_salary)
values(#{empName},#{empSalary})
insert>
@Test
public void testSaveEmp() {
EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);
Employee employee = new Employee();
employee.setEmpName("john");
employee.setEmpSalary(666.66);
employeeMapper.insertEmployee(employee);
log.info("employee.getEmpId() = " + employee.getEmpId());
}
注意
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>
insertUser
的插入语句来将 User
对象插入到 user
表中。我们使用 selectKey
来查询 UUID 并设置到 id
字段中。keyProperty
属性来指定查询到的 UUID 赋值给对象中的 id
属性,而 resultType
属性指定了 UUID 的类型为 java.lang.String
。selectKey
放在了插入语句的前面,这是因为 MySQL 在 insert
语句中只支持一个 select
子句,而 selectKey
中查询 UUID 的语句就是一个 select
子句,因此我们需要将其放在前面。User
对象插入到 user
表中时,我们直接使用对象中的 id
属性来插入主键值。
<select id="selectEmployee" resultType="com.alex.mybatis.entity.Employee">
select emp_id empId,emp_name empName,emp_salary empSalary from t_emp where emp_id=#{maomi}
select>
关于实体类属性的约定:
getXxx()方法、setXxx()方法把方法名中的get或set去掉,首字母小写。
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
settings>
<select id="selectEmployee" resultType="com.alex.mybatis.entity.Employee">
select emp_id,emp_name,emp_salary from t_emp where emp_id=#{empId}
select>
<resultMap id="selectEmployeeByRMResultMap" type="com.alex.mybatis.entity.Employee">
<id column="emp_id" property="empId"/>
<result column="emp_name" property="empName"/>
<result column="emp_salary" property="empSalary"/>
resultMap>
<select id="selectEmployeeByRM" resultMap="selectEmployeeByRMResultMap">
select emp_id,emp_name,emp_salary from t_emp where emp_id=#{empId}
select>