mybatis03_配置文件
一、核心配置详解
这里只写几个个人认为比较常用的,具体的官网上面有明确的说明
1、properties
这些属性可以在外部进行配置,并可以进行动态替换。个人感觉最常用的作用就是吧数据源内的硬编码提取出来。
我们可以再创建一个mysql.properties文件用于存放数据库的信息,方便我们更改数据库信息,更改后的配置文件和数据库文件如下:
mysql.url = jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8
mysql.driver = com.mysql.cj.jdbc.Driver
mysql.username = root
mysql.passwd = passwd
在properties标签中有resource和url两个属性用于指定你写的配置在哪儿,我们可以用上文就提到过的方式${}进行取值。
<configuration>
<properties resource="mysql.properties"></properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${mysql.driver}"/>
<property name="url" value="${mysql.url}"/>
<property name="username" value="${mysql.username}"/>
<property name="password" value="${mysql.passwd}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- <mapper class="com.ls.dao.BookDao"></mapper>-->
<package name="com.ls.dao"/>
</mappers>
</configuration>
2、environments
看名字就知道这里面可以包含多个environment,这能够方便我们切换不同的数据源,测试、生产、和开发用的数据库肯定是不一样的,如果想切换数据源直接更改environments的default的值即可,下面的代码块配置两个数据源,在实际使用时我们用的是id为product的数据库。同时environment标签中有 transactionManager type=" " 用于切换事务管理器(不同数据库的事务管理器也不一样,下面代码块是我瞎写的,理解这个意思就行)。
<environments default="product">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${mysql.driver}"/>
<property name="url" value="${mysql.url}"/>
<property name="username" value="${mysql.username}"/>
<property name="password" value="${mysql.passwd}"/>
</dataSource>
</environment>
<environment id="product">
<transactionManager type="ODBC" />
<dataSource type="POOLED">
<property name="driver" value="${mysql.driver}"/>
<property name="url" value="${mysql.url}"/>
<property name="username" value="${mysql.username}"/>
<property name="password" value="${mysql.passwd}"/>
</dataSource>
</environment>
</environments>
3、别名typeAliases
在我们编写mapper映射文件时,如果需要写入参或者出参类型的话都是写全路径名称,有提示还好,我这一版他没提示,所以我们可以给这些类其一个简单的别名,在mybatis-config.xml有这么一个标签
<typeAliases>
<typeAlias alias="book" type="com.ls.model.Book"/>
</typeAliases>
在这个typeAliases标签中就可以给类起别名辣,不过不是很推荐这个用法,如果你有mybatisX插件的话你可以直接互相定位dao和xml的映射关系,但如果你没有装插件的话你想在mapper文件找到你的接口的话那不得根据包名找吗,所以不起别名从我做起。
<mapper namespace="com.ls.dao.BookDao">
<insert id="add" parameterType="com.ls.model.Book">
<selectKey keyProperty="bookId" order="AFTER" resultType="int">
select last_insert_id()
</selectKey>
insert into book (book_name,book_author,create_time,update_time)
values (#{bookName},#{bookAuthor},#{createTime},#{updateTime})
</insert>
</mapper>
同时对于一些基本类型,mybatis已经给你提前写好别名了(但是我强迫症喜欢写全路径的),can can 下面,喜欢吗,官网截图的:
二、映射文件
映射文件是我们写sql语句的地方,在传统的JDBC编程中,我们一般会在数据持久层创建一个XxxDao,然后再dao包下创建impl包来实现我们XxxDao中的方法。Mybatis提供了映射的方式来代替传统的JDBC编程,这里的映射即为实体类与数据库表中记录的对应关系(上面纯属个人理解)。
1、在mybatis-config.xml中添加映射
在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。一般有以下三种方式,这里最推荐第一种方式,毕竟可以全自动的扫描:
<!-- 将包内的映射器接口全部注册为映射器 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
</mappers>
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
</mappers>
推荐一开始就把包建好把映射配置到mybatis-config.xml文件中在去干别的,因为真有可能忘记而报错,你还看不出来哪儿有问题。(也可能是我是个笨b看不出来报错信息)。
2、创建新项目
为了方便下面入参、出参还有动态sql部分的笔记,我们再创建一个新的数据库和项目。这里只给出项目结构和主要类,其他工具、配置可移步到上一篇博客,Mapper代理开发。https://www.cnblogs.com/purearc/p/17195977.html
⬇️数据库
CREATE TABLE `emp` (
`emp_id` bigint NOT NULL AUTO_INCREMENT,
`emp_name` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
`address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
`email` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`emp_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
⬇️ POJO(Plain Ordinary Java Object)类(在java开发手册嵩山版中POJO专指只有 setter/getter/toString 的 简单类,包括 DO/DTO/BO/VO 等。)
/**
* date: 2023/3/2
*
* @author Arc
*/
package com.ls.pojo;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
@Data
@Accessors(chain = true)
public class Emp {
private Long empId;
private String empName;
private String address;
private String email;
private Date createTime;
private Date updateTime;
}
⬇️mapper映射文件(完整)
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ls.mapper.EmpMapper">
<insert id="add" parameterType="com.ls.pojo.Emp">
insert into emp (emp_id,emp_name,address,email,create_time,update_time)
values (#{empId},#{empName},#{address},#{email},#{createTime},#{updateTime});
</insert>
<select id="findByNameAndAddress" parameterType="map" resultType="com.ls.pojo.Emp">
select emp_id empId,emp_name empName,address,email,create_time createTime,update_time updateTime
from emp
where emp_name like concat('%',#{empName},'%')
and address like concat('%',#{address},'%');
</select>
</mapper>
⬇️EmpMapper:
package com.ls.mapper;
import com.ls.pojo.Emp;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
public interface EmpMapper {
/**
* 添加员工
* @param emp
* @return
*/
int add(Emp emp);
/**
* 根据姓名和住址找
* @param params
* @return
*/
List<Emp> findByNameAndAddress(Map<String,Object> params);
/**
*
* @param empName
* @param address
* @return
*/
List<Emp> findByNameAndAddress2(@Param("empName") String empName, @Param("address") String address);
/**
* 根据id查找
* @param empId
* @return
*/
Emp selectById(long empId);
}
⬇️测试程序(完整)
/**
* date: 2023/3/2
*
* @author Arc
*/
package com.ls.service;
import com.ls.mapper.EmpMapper;
import com.ls.pojo.Emp;
import com.ls.util.MybatisUtil;
import org.apache.ibatis.session.SqlSession;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class EmpService {
public static void main(String[] args) {
// testAdd();
// testFindByNameAndAdress2();
testSelect();
}
private static void testSelect() {
SqlSession sqlSession = null;
try {
sqlSession = MybatisUtil.getSqlSession();
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = empMapper.selectById(1L);
System.out.println(emp);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
/**
* 测试传参map
*/
private static void testFindByNameAndAdress() {
SqlSession sqlSession = null;
try {
sqlSession = MybatisUtil.getSqlSession();
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
Map<String, Object> params = new HashMap<>();
params.put("empName","不举");
params.put("address","大学");
// System.out.println(params);
List<Emp> empList = empMapper.findByNameAndAddress(params);
for (Emp emp : empList) {
System.out.println(emp);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
/**
* 注解传参
*/
private static void testFindByNameAndAdress2() {
SqlSession sqlSession = null;
try {
sqlSession = MybatisUtil.getSqlSession();
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
// System.out.println(params);
List<Emp> empList = empMapper.findByNameAndAddress2("不举","齐鲁");
for (Emp emp : empList) {
System.out.println(emp);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
/**
* 测试添加
*/
private static void testAdd() {
SqlSession sqlSession = null;
try {
sqlSession = MybatisUtil.getSqlSession();
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
Emp emp = new Emp().setEmpName("庄不举").setAddress("齐鲁工业大学").setEmail("zxj@163.com")
.setCreateTime(new Date()).setUpdateTime(new Date());
int result = empMapper.add(emp);
sqlSession.commit();
System.out.println(result > 0 ? "success" : "fail");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
}
3、入参
前面我们已经尝试过把自己定义的类当作入参,但是实际情况可能有更加复杂的参数,比如说我们要同时查找Emp表中姓名和住址都符合的一条数据,那就需要传入两个参数,我们可以用map来封装(这里的map就是mybatis给他起的别名):
<select id="findByNameAndAddress" parameterType="map" resultType="com.ls.pojo.Emp">
select emp_id empId,emp_name empName,address,email,create_time createTime,update_time updateTime
from emp
where emp_name like concat('%',#{empName},'%')
and address like concat('%',#{address},'%');
</select>
需要注意我们在mapper映射文件中取的是map中的key,将我们要查找的条件放入自己定义好的map,再把这个叫params的map传到mapper文件中处理,就可以返回满足两个条件的了。
private static void testFindByNameAndAdress() {
SqlSession sqlSession = null;
try {
sqlSession = MybatisUtil.getSqlSession();
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
Map<String, Object> params = new HashMap<>();
params.put("empName","不举");
params.put("address","大学");
// System.out.println(params);
List<Emp> empList = empMapper.findByNameAndAddress(params);
for (Emp emp : empList) {
System.out.println(emp);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
⬇️传入的两个参数
如果你不想用map的话,我们还可以通过注解的形式穿两个参数:
/**
*
* @param empName
* @param address
* @return
*/
List<Emp> findByNameAndAddress2(@Param("empName") String empName, @Param("address") String address);
在mapper文件中取值符号内是@Param注解内的值,由于使用了注解,这里的paramType就不需要写了,写了也没作用。(至少我写map没报错,可能是注解导致失效了)
<select id="findByNameAndAddress2" parameterType="map" resultType="com.ls.pojo.Emp">
select emp_id empId,emp_name empName,address,email,create_time createTime,update_time updateTime
from emp
where emp_name like concat('%',#{empName},'%')
and address like concat('%',#{address},'%');
</select>
在下面的测试程序中,我们传入的是两个String类型的字符串。
/**
* 注解传参
*/
private static void testFindByNameAndAdress2() {
SqlSession sqlSession = null;
try {
sqlSession = MybatisUtil.getSqlSession();
EmpMapper empMapper = sqlSession.getMapper(EmpMapper.class);
// System.out.println(params);
List<Emp> empList = empMapper.findByNameAndAddress2("不举","齐鲁");
for (Emp emp : empList) {
System.out.println(emp);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
4、出参
出参可以是基本数据类型或者自定义数据类型,也可以是map,在我们写select *的时候因为mysql和java中对变量名称的规范不同,所以会给变量起一个别名(不起别名是nulli,如下图)。
这时候就可以自定义一个resultMap来对应数据表和实体类的名称。
<resultMap id="EmpMap" type="com.ls.pojo.Emp">
<id property="empId" column="emp_id"></id>
<result property="empName" column="emp_name"></result>
<result property="updateTime" column="update_time"></result>
<result property="createTime" column="create_time"></result>
</resultMap>
<select id="selectById" resultMap="EmpMap">
select *
from emp
where emp_id = #{empId}
</select>
自然你也可以把这个本来返回值是Emp类型的方法定义为map类型的,毕竟这个类本身就是一个map。
/**
* 根据id查找
* @param empId
* @return
*/
Emp selectById(long empId);
————————————————————————————————————
Map<Emp> selectById2(long empId);