Mybatis框架学习--中
Mybatis框架学习----(2)
1. Mybatis的自定义分析
1. 第一步
SqlSessionFactoryBuilder接受SqlMapConfig.xml的文件流,构建出SqlSessionFactory对象
2. 第二步
SqlSessionFactory读取SqlMapConfig.xml中连接数据库和mapper的映射信息,用来生产出真正操作数据库的SqlSession对象
3. 第三步
SqlSession对象的两大作用:1) 生产接口代理对象;2) 定义通用增删改查方法
注意:两者除了获取数据库信息,还需要得到sql语句
4. 第四步
作用1)
在SqlSessionImpl对象中(SqlSession的实现类对象)的getMapper方法分为两步骤:1) 用SqlSessionFactory读取数据库连接信息创建Connection对象;2) 通过jdk代理模式创建出代理对象作为getMapper方法的返回值,主要工作是在创建对象时第三个参数InnovationHandler接口的重写处理类里面得到sql语句,执行对象的CURD操作
作用2)
在SqlSessionImpl对象中提供selectList方法[其实在Mybatis框架中还有selectOne,insert等方法,同样分为两步走]:1) 用SqlSessionFactory读取的数据库连接信息创建出JDBC的Connection对象;2) 直接得到Sql语句,使用JDBC的Connection对象进行CRUD操作
5. 第五步
封装结果集:无论使用分支一生成代理对象,还是直接使用分支二提供的通用CRUD方法,都要对返回的数据库结果进行封装,变成java对象返回给调用者,所以需要知道调用者所需的返回值类型(封装成什么类的对象)
总结: 无论是让Mybatis帮助创建代理对象还是直接使用Mybatis提供的CRUD方法,其本质都是得到JDBC的Connection对象,执行对应的sql语句,最终封装到结果集。只是注解和xml配置两种开发模式在传递sql语句和返回值类型的方式上有所差异:
- 注解的SQL语句获取是在Dao接口方法名上的@Select注解中,返回值类型根据方法名的返回值类型来获取
- xml配置方式:在Dao接口的xml配置中,从resultType中获取返回值类型,并且获取其sql语句
2. Mybatis实现CRUD操作
1. 在之前的入门案例中的Dao接口中增加一个saveUser的抽象方法
/**
* 用户的持久层接口
*
*/
public interface UserInterface {
/**
* 查询所有用户操作
* @return
*/
//@Select("select * from account") // 对于使用注解来配置UserDao
List<User> findAll();
void saveUser(User user); // 新增用户方法
void updateUser(User user); // 更新用户方法
void deleteUser(Integer UserId); // 删除用户方法
}
2. 在Dao接口的XML配置文件中,增加更新的sql语句
3. 在Dao接口的XML配置文件中,增加删除的sql语句
<?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">
<!-- namespace名称空间,Dao接口的全类名,告诉mybatis这个配置文件是实现哪个接口的-->
<mapper namespace="com.huzhen.domain.dao.UserInterface">
<!-- 配置查询表user所有记录的sql语句 并且加上resultType返回值类型,sql语句的查询结果集将会被封装到
User类中,最终返回一个List<User>列表-->
<select id="findAll" resultType="com.huzhen.domain.User">
select * from account;
</select>
<insert id="saveUser" parameterType="com.huzhen.domain.User">
insert into account(username, birthday, sex, addres) values(#{username},
#{birthday}, #{sex}, #{addres});
</insert>
<update id="updateUser" parameterType="com.huzhen.domain.User">
update account set username=#{username}, birthday=#{birthday}, sex=#{sex},
addres=#{addres} where id=#{id};
</update>
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from account where id=#{Uid}
</delete>
</mapper>
注意:在JDBC中可以使用?来进行占位符,
insert into account values(?, ?, ?, ?)
而Mybatis中是通过增加**parameterType参数用来指定传递进来的参数是User类型下的参数,并且只有使用jdk自带的getter和Setter方法生成的获取参数和返回参数方法,才能使用#{}**来传递参数,否则需要指定get和Set的方法名而不是成员变量名。在删除的配置中,传入的parameterType中不再是自定义的封装类User而是根据什么来查询,这里根据id来查询,则传入进去的是Integer整型,如果是根据username或者其他的可以传入String类型。
-
parameterType和resultType的区别在于:如果该sql语句有输入,则指明parameterType,有输出则指明resultType
-
在test包下增加一个用于测试的类,由于安装的依赖是Junit版本是5.8.2,不能再使用注解==@BeforeAll和@AfterAll>==
而只能使用@BeforeAll和BeforeAll,并且这两个注解只能修饰静态方法,所以在成员变量处也需要设置static修饰符。之前对于读取配置文件,获取SqlSessionFactory来创建SqlSession对象,获取Dao接口的代理对象以及释放资源是单个写的,现在对于多个测试案例,可以将共用方法进行封装到init和close方法中,需要注意的是对于增加,删除和更新操作时,需要进行事务提交才能正常运行。
4. test类中进行增删改的测试
public class test {
/**
* 由于需要测试多个操作,而每个test中读取配置文件,获取SqlSessionFactory来创建对象SqlSession
* 以及获取Dao的代理对象和释放资源都是共用的,所以可以封装在一个init方法中
*/
private static InputStream is;
private static SqlSession sqlSession;
private static UserInterface userDao;
@BeforeAll
public static void init() throws IOException {
is = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
sqlSession = factory.openSession();
userDao = sqlSession.getMapper(UserInterface.class);
}
// AfterAll和BeforeAll注解修饰的必须是静态方法
@AfterAll
public static void close() throws IOException{
sqlSession.commit(); // 对于更新,插入,删除操作必须有提交事物才能正常运行
sqlSession.close();
is.close();
}
/**
* 测试查询所有用户
*/
@Test
public void testFindAll(){
List<User> list = userDao.findAll();
for(User user : list){
System.out.println(user);
}
}
/**
* 测试新增用户
*/
@Test
public void testInsertUser(){
User user = new User();
user.setUsername("Bin");
user.setBirthday(new Date());
user.setSex("男");
user.setAddres("上海虹桥");
userDao.saveUser(user);
// 必须需要提交事物才能添加成功,在close中执行
System.out.println("添加成功!");
}
@Test
public void testUpdate(){
User user = new User();
user.setId(19);
user.setUsername("A Bin");
user.setBirthday(new Date());
user.setSex("男");
user.setAddres("上海滴水湖");
userDao.updateUser(user);
}
@Test
public void testUser(){
userDao.deleteUser(19);
}
}
5. 关于增加用户的SQL语句深入
新增用户后,同时需要返回当前新增用户的id值,因为id是由数据库的**AUTO_INCREMENT**实现的。所以相当于在新增用户将自动增长auto_increment的值返回。
那么在XML中的insert标签中需要加入select last_insert_id()语句:
<insert id="saveUser" parameterType="com.huzhen.domain.User">
<!-- keyProperty表示返回的值名称对应实体类USer keyColumn对应表中的id order取值为after表示插入后的行为 -->
<selectKey keyProperty="id" keyColumn="id" order="AFTER" resultType="INT">
select last_insert_id();
</selectKey>
insert into account(username, birthday, sex, addres) values(#{username},
#{birthday}, #{sex}, #{addres});
</insert>
其中,**keyProperty表示返回值名称对应的是实体类User中的id,而KeyColumn对应的是表中的字段id,order表示下面的语句是在插入前执行还是在插入后执行,这里赋值AFTER**表示在查询之后返回id值
在test类中进行测试代码如下:
@Test
public void testInsertUser(){
User user = new User();
user.setUsername("Bin");
user.setBirthday(new Date());
user.setSex("男");
user.setAddres("上海虹桥");
System.out.println("插入用户前:" + user);
userDao.saveUser(user);
// 必须需要提交事物才能添加成功,在close中执行
System.out.println("添加成功!");
System.out.println("插入用户后:" + user);
}
输出结果为:
可以看出插入前后id的改变
6. 根据Id查询和模糊查询, 聚合函数查询
和上面一样,首先在Dao接口中定义方法名,其次在XML配置文件中加入sql语句,最后在测试类中进行测试:
public interface UserInterface {
/**
* 定义sql语句的方法
* @return
*/
//@Select("select * from account") // 对于使用注解来配置UserDao
List<User> findAll(); // 查询所有用户
void saveUser(User user); // 新增用户方法
void updateUser(User user); // 更新用户方法
void deleteUser(Integer UserId); // 删除用户方法
User findById(Integer userId); // 根据id查询用户信息
List<User> findByName(String userName); // 根据用户名模糊查询
int findTotalUser(); // 查询用户的总记录数
}
<select id="findById" parameterType="INT" resultType="com.huzhen.domain.User">
select * from account where id=#{Uid};
</select>
<select id="findByName" parameterType="String" resultType="com.huzhen.domain.User">
select * from account where username like #{name};
<!-- select * from account where username like '%${value}%' -->
</select>
<select id="findTotalUser" resultType="java.lang.Integer">
select count(id) from account;
</select>
- 对于查询单个用户的这里是根据id来查询,所以parameterType的参数为int,返回是一个User对象,在测试类中:
@Test
public void testSelectById(){
User user = userDao.findById(2);
System.out.println(user);
}
查询结果为:
-
对于模糊查询,分为两种情况
- i ) 在xml中不设置%模糊查询,
select * from account where username like #{name};
在测试类中进行模糊查询的操作:List<User> list = userDao.findByName("%User%");
- ii) 另一种则是在xml设置模糊查询,使用**’%
v
a
l
u
e
{value}%'</span>**:`select * from account where username like '%
value{value}%'
, 而在测试类中则无需在使用模糊查询了:
List list = userDao.findByName(“User”);`
但是两者存在区别:对于i) 读取到的sql语句为:
select * from account where username like '%王%'
;而对于ii) 读取到的sql语句是:select * from account where username like ?
配置文件的模糊查询得到的是Statement对象的字符串拼接SQl,而测试类的模糊查询得到的是PreparedStatement的参数占位符,因此不推荐在配置文件中使用模糊查询,易引起sql注入问题 - i ) 在xml中不设置%模糊查询,
查询结果为:
- 对于聚合函数的查询,由于查询的是用户的总记录数,因此在返回值类型resultType中设置为INT或者java.lang.Integer均可,在测试类:
@Test
public void testTotalUserNumber(){
int number = userDao.findTotalUser();
System.out.println("总记录数:" + number);
}
查询结果为:
3. Mybatis的参数深入
3.1. Mybatis的参数
3.1.1. ParameterType输入类型
3.1.2. 传递简单类型
- 传递INT类型的id
- 传递模糊查询的String username
- 传递实体类型的User
3.1.3. 传递pojo对象
Mybatis使用**OGNL**表达式解析对象字段的值,#{}或者${}括号中的值为pojo属性名称
OGNL:Object Graphic Navigation Languag 对象图导航语言,通过对象的取值方法来获取数据,在写法上将get给省略了,如:获取用户名称
在USer类中:user,getUsername();
OGNL表达式写法:user.username();
Mybatis中为什么可以直接写username
,而不使用 user.
?
因为在parameterType中已经提供了属性所属的类,如:com.huzhen.domain.User
,所以不再需要写对象名
3.1.4. 传递pojo包装对象
开发中通过pojo传递查询条件,查询条件是综合的查询条件,不仅包括用户查询条件还包括其他的查询条件(如将用户购买商品信息也作为查询条件),此时可以使用包装对象传递输入参数。
Pojo类中包含pojo
需求:根据用户名来查询用户信息,查询条件放到QueryVo的user属性中
目的:将实体类对象user再封装一层,适用于由多个实体类对象组合成一个查询条件来实现数据的查询
在Dao接口中增加一个方法:
// 根据queryVo中的条件查询用户: 将实体类对象再封装一层,应用在由多个对象组成一个查询条件来实现数据的查询
List<User> findUserByVo(QueryVo vo);
这里的QueryVo类需要自己定义,由于这里只涉及到一个实体类对象,那么成员变量只有一个user,在domain包下定义:
public class QueryVo {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
进而在XML文件中进行配置,注意这里的查询返回值不能再是User,由于传递进去的是vo对象,所以应该是:
<!-- 根据queryVo的条件查询用户 -->
<select id="findUserByVo" parameterType="com.huzhen.domain.QueryVo" resultType="com.huzhen.domain.User">
select * from account where username like #{user.username};
</select>
另外,在模糊查询中的#{}参数不能直接用username,因为在queryVo类中找不到username这个属性,应该由vo对象的属性user来找到username: #{user.username}.
3.2. Mybatis的输出结果封装(resultType)
3.2.1. 输出简单类型
- 输出的可以是int类型,如:
select count(id) from account;
- 输出的可以是User类型,如:
select * from account;
==注意:==输出简单类型必须查询出来的结果集只有一条记录,最终将第一个字段的值转换为输出类型,使用session的selectOne可查询单条记录。
3.2.2. 输出pojo类型
3.2.3. 输出pojo列表
注意:当查询封装结果集时,要求实体类User的属性必须与数据库中的列名保持一致,如果不一致,那么,需要修改的地方有:
public class User implements Serializable {
private Integer userId;
private String userName;
private Date userBirthday;
private String userSex;
private String userAddres;
- 测试类中调用get和set的方法名需要更改
- xml文件中关于增删改中,keyProperty的属性值不再是id而是userId,另外,在values中会找对应的OGNL表达式,以前的#{id},#{birthday}找不到了,需要改成实体类中对应的属性名==#{userId},#{userBirthday}==
<insert id="saveUser" parameterType="com.huzhen.domain.User">
<!-- keyProperty表示返回的值名称对应实体类USer keyColumn对应表中的id order取值为after表示插入后的行为 -->
<selectKey keyProperty="id" keyColumn="id" order="AFTER" resultType="INT">
select last_insert_id();
</selectKey>
insert into account(username, birthday, sex, addres) values(#{username},
#{birthday}, #{sex}, #{addres});
</insert>
<update id="updateUser" parameterType="com.huzhen.domain.User">
update account set username=#{username}, birthday=#{birthday}, sex=#{sex},
addres=#{addres} where id=#{id};
</update>
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from account where id=#{Uid};
</delete>
- 对于查询语句findAll,并不会正确的返回用户列表,返回的结果为:
除了username的属性可以得到,其他属性值均不能正确得到,因为windows中的mysql是不区分大小写的,所以将username与userName识别为同一个属性,因此可以正确返回,而其他的属性值在数据库中找不到对应的列。
那么,解决方法有:
- 针对sql语句,对属性名起别名的方式来解决:select id as userId, birthday as userBirthday, sex as userSex, addres as userAddres from account; 这种解决方法执行效率快,但是开发过程麻烦,代码冗余
- 在Dao接口的xml配置文件中,增加一个resultMap配置,如下:
<resultMap id="userMap" type="com.huzhen.domain.User">
<!-- 主码的配置 property对应实体类中的属性 column对应数据库的列名 -->
<id property="userId" column="id"></id>
<!-- 非主码的配置 -->
<result property="userName" column="username"></result>
<result property="userSex" column="sex"></result>
<result property="userBirthday" column="birthday"></result>
<result property="userAddres" column="addres"></result>
</resultMap>
<!-- 注意:当使用配置来连接实体类属性名和数据库列名时候,查询xml不能再使用resultType,而是resultMap -->
<select id="findAll" resultMap="userMap">
select * from account;
</select>
其中,id为该map的名字,type依旧是实体类User;需要注意的是:在以后的sql配置中,不能在使用resultType来进行User类型的返回值的赋值,而是采用resultMap来进行返回,对应上面定义的resultMap方法名id。该种方法开发效率高,但由于会多解析一段xml配置,因此执行效率较低。
4. Mybatis实现Dao层开发
使用Mybatis开发Dao,通常有两个方法:原始Dao开发和Mapper接口代理开发。现在主流的是接口代理开发方式。
4.1. Mybatis实现Dao的传统开发方式
4.2. 自定义Dao实现类的Mybatis的执行过程
SqlSession中封装了对数据库的CRUD操作,通过SqlSessionFactory创建SqlSession,而SqlSessionFactory是通过SqlSessionFactoryBuilder创建
自定义实现Dao的实现类来分析Mybatis是如何使用动态代理来执行sql语句的:
在Dao.impl包下创建一个Dao接口的实现类UserDaoImpl:
public class UserDaoImpl implements UserInterface{
private SqlSessionFactory factory;
public UserDaoImpl(SqlSessionFactory factory){
this.factory = factory;
}
@Override
public List<User> findAll() {
SqlSession session = factory.openSession();
// factory 获取sqlsession对象,调用其中的selectList方法返回输出列表
// 传递的参数为: Dao接口的全限定类名.方法名
List<User> list = session.selectList("com.huzhen.dao.UserInterface.findAll");
session.close();
return list;
}
@Override
public void saveUser(User user) {
SqlSession session = factory.openSession();
// 对于insert方法需要多传递一个user对象
session.insert("com.huzhen.dao.UserInterface.saveUser", user);
session.commit();
session.close();
}
@Override
public void updateUser(User user) {
SqlSession session = factory.openSession();
session.update("com.huzhen.dao.UserInterface.updateUser", user);
session.commit();
session.close();
}
@Override
public void deleteUser(Integer UserId) {
SqlSession session = factory.openSession();
session.update("com.huzhen.dao.UserInterface.deleteUser", UserId);
session.commit();
session.close();
}
@Override
public User findById(Integer userId) {
SqlSession session = factory.openSession();
User user = session.selectOne("com.huzhen.dao.UserInterface.findById", userId);
session.close();
return user;
}
@Override
public List<User> findByName(String userName) {
SqlSession session = factory.openSession();
List<User> list = session.selectList("com.huzhen.dao.UserInterface.findByName", userName);
session.close();
return list;
}
@Override
public int findTotalUser() {
SqlSession session = factory.openSession();
Integer count = session.selectOne("com.huzhen.dao.UserInterface.findTotalUser");
return count;
}
}
覆盖重写Dao接口的抽象方法,在构造函数中传递一个SqlSessionFactory对象,用来创建SqlSession对象,来执行sql语句。对于查询的结果集只有一个记录,使用Session的selectOne方法(返回一个用户,或者一个聚合函数的值总数目等),如果某个方法有输入参数,那么在调用Session的方法时需要将该参数传递,如:session.insert("com.huzhen.dao.UserInterface.saveUser", user);
User user = session.selectOne("com.huzhen.dao.UserInterface.findById", userId);
。
在测试类中的实现如下:
public class test {
/**
* 由于需要测试多个操作,而每个test中读取配置文件,获取SqlSessionFactory来创建对象SqlSession
* 以及获取Dao的代理对象和释放资源都是共用的,所以可以封装在一个init方法中
*/
private static InputStream is;
private static UserInterface userDao;
@BeforeAll
public static void init() throws IOException {
is = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
// 使用工厂对象创建dao对象
userDao = new UserDaoImpl(factory);
}
// AfterAll和BeforeAll注解修饰的必须是静态方法
@AfterAll
public static void close() throws IOException{
is.close();
}
/**
* 测试查询所有用户
*/
@Test
public void testFindAll(){
List<User> list = userDao.findAll();
for(User user : list){
System.out.println(user);
}
}
/**
* 测试新增用户
*/
@Test
public void testInsertUser(){
User user = new User();
user.setUsername("Bin");
user.setBirthday(new Date());
user.setSex("男");
user.setAddres("上海虹桥");
System.out.println("插入用户前:" + user);
userDao.saveUser(user);
// 必须需要提交事物才能添加成功,在close中执行
System.out.println("添加成功!");
System.out.println("插入用户后:" + user);
}
@Test
public void testUpdate(){
User user = new User();
user.setId(21);
user.setUsername("The shy");
user.setBirthday(new Date());
user.setSex("男");
user.setAddres("上海滴水湖");
userDao.updateUser(user);
}
@Test
public void testDeleteUser(){
userDao.deleteUser(21);
}
@Test
public void testSelectById(){
User user = userDao.findById(2);
System.out.println(user);
}
@Test
public void testSelectByName(){
List<User> list = userDao.findByName("%User%");
for(User user : list){
System.out.println(user);
}
}
@Test
public void testTotalUserNumber(){
int number = userDao.findTotalUser();
System.out.println("总记录数:" + number);
}
}
由于已经在Dao的实现类中定义了SqlSession对象,所以在测试类中的init函数中无需再根据factory来创建sqlSession,直接创建一个Dao接口的实现类对象来执行sql语句,不过在创建Dao对象时,需要传递一个factory对象。
通过debug,流程图:
当找到PreparedStatement对象时,才是JDBC中执行sql语句的方式,而关于PreparedStatement对象的执行方法有三种:
- execute: 能执行CRUD中的任意一种语句,返回一个布尔值,表示是否有结果集,有结果集返回true否则返回false
- executeUpdate: 无法执行查询语句,返回的是影响数据库记录的行数
- executeQuery: 只能执行select语句,无法执行增删改,执行结果为封装的ResultSet对象
4.3. 代理Dao的Mybatis的执行过程
Mybatis可以使用Session.getMapper来获取Dao接口的代理对象,来帮助我们调用执行sql语句的方法,其具体流程为:
在进入到MapperProxyFactory类中的newInstance方法中可以看到使用了动态代理**Proxy.newProxyInstance,重点关注第三个参数mapper Proxy,是接口InvocationHandler的实现类,调用了invoke方法,而invoke方法中的execute方法中执行了insert,update,delete以及selectList**方法,这才是执行sql语句的方法。
5. SqlMapConfig.xml配置文件
5.1. 配置内容
SqlMapConfig.xml中配置的内容和顺序如下:
- properties 属性
- settings 全局配置参数
- typeAliases 类型别名
- typeHandlers 类型处理器
- objectFactory 对象工厂
- plugins 插件
- environments 环境集合属性对象
- environment 环境子属性对象
- transactionManager 事务管理
- dataSource 数据源
- mappers 映射器
5.2. properties (属性)
SqlMapConfig.xml可以引用java属性文件的配置信息:
jdbc.deriver=com.mysql.cj.jdbc.Driver
jdbc.url=mysql://localhost:3306/eesy?serverTimezone=UTC&useSSL=false
jdbc.username=root
jdbc.password=root
SqlMapConfig.xml引用如下:
<?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>
<!-- 配置连接数据库的4个基本信息:驱动, url, 用户名以及密码-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/eesy?serverTimezone=UTC&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</properties>
<!-- 配置环境-->
<environments default="mysql">
<!-- 配置mysql的环境-->
<environment id="mysql">
<!-- 配置事务的类型-->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源(数据库连接池)-->
<dataSource type="POOLED">
<!-- 配置连接数据库的4个基本信息:驱动, url, 用户名以及密码-->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- 指定映射配置文件的位置,映射配置文件即为每个dao独立的配置文件
如果是使用注解来配置,此处应该使用class属性指定被注解的dao全限定类名即dao下面的接口的全类名-->
<mappers>
<mapper resource="com/huzhen/dao/UserDaoImpl.xml"></mapper>
<!-- <mapper class="com.huzhen.domain.dao.UserInterface"></mapper>-->
</mappers>
</configuration>
显然,在environment中的property中的value对应着properties中的name,这样做虽然可以正确执行,但是没有必要。更多的是在properties属性,可以在标签内部配置连接数据库的信息, 也可以通过属性引用外部配置文件jdbcConfig.properties:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/eesy?serverTimezone=UTC&useSSL=false
jdbc.username=root
jdbc.password=123456
- resources属性:用于指定配置文件的位置,是按照类路径写法,并且放在resources的类路径下。
<!-- 引用外部配置文件信息 -->
<properties resource="jdbcConfig.properties"></properties>
<!-- 配置环境-->
<environments default="mysql">
<!-- 配置mysql的环境-->
<environment id="mysql">
<!-- 配置事务的类型-->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源(数据库连接池)-->
<dataSource type="POOLED">
<!-- 配置连接数据库的4个基本信息:驱动, url, 用户名以及密码-->
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
注意property中的value不能直接写url等,而是写jdbcConfig中对应的name。
- url属性:要求按照url格式书写地址,包括:协议 + 主机地址 + 端口号 + URI(统一资源标识符)
window默认地址路径是file协议,如下:
所以,在XML配置文件中的url定义为:
<properties url="file:///D:/java/Mybatis_Dao/src/main/resources/jdbcConfig.properties"></properties>
同样实现和resource加载配置文件的效果,另外在mapper中读取Dao接口配置文件的方法也可以使用url地址来读取:
<mapper url="file:///D:/java/Mybatis_Dao/src/main/resources/com/huzhen/dao/UserDaoImpl.xml"></mapper>
5.3. typeAliases(domain类中的别名)
在SqlMapConfig.xml配置文件中加入typeAliases:
<!-- 使用typeAliases配置别名,只能配置domain中类的别名 -->
<typeAliases>
<typeAlias type="com.huzhen.domain.User" alias="user"></typeAlias>
</typeAliases>
其中,typeAlias用于配置别名,type属性指定的是domain下的实体类的全限定类名,alias为指定类名,当指定了别名就不再区分大小写,在sql语句中的resultType或者parameterType中就可以不用再写User的全限定类名,直接写user即可:
<select id="findAll" resultType="user">
select * from account;
</select>
如果,domain包下存在多个实体类,一个一个去定义比较麻烦,可以在typeAliases标签下使用package包,
<!-- 使用typeAliases配置别名,只能配置domain中类的别名 -->
<typeAliases>
<package name="com.huzhen.domain"></package>
</typeAliases>
用于指定配置别名的包,指定之后,domain包下的所有类名均是别名,不再区分大小写。