1. 知识回顾
1.1 回顾自定义Mybatis流程分析
1.2 回顾Mybatis环境搭建-以及实现查询所有的功能
- 创建一个maven 工程 ,不使用骨架 。直接选择maven之后点击next即可:
填写自己的groupId(域名反写) 和 ArtifactId (项目名称);
设置项目的打包方式为 jar ;
jar
- 导入依赖 ,Mybatis 依赖 、MySql驱动依赖、log4j依赖、junit单元测试依赖;
org.mybatis
mybatis
3.4.5
mysql
mysql-connector-java
5.1.6
log4j
log4j
1.2.17
junit
junit
4.13
- 编写User实体类 并实现 Serializable 序列化接口
/**
* User实体类
*/
public class User implements Serializable{
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
// 省略setter 和 getter 方法
// 省略 toString方法
}
- 编写 UserDao 持久层接口
public interface UserDao {
/**
* 查询所有用户信息
* @return
*/
List findAll();
}
- 在resources 目录下创建 SqlMapConfig.xml全局配置文件 并 导入相关约束
- 在SqlMapConfig.xml文件中配置相关属性
- 在 resources 目录下创建 与 UserDao.java 持久层接口目录相同的UserDao.xml映射配置文件;
- 编写测试类
/**
* mybatis回顾 测试类
*/
public class MybatisLookBackTest {
@Test
public void testSelectList() throws IOException {
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
SqlSession session = factory.openSession();
UserDao userDao = session.getMapper(UserDao.class);
List users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
session.close();
}
}
2. Mybatis的CRUD操作
2.1 Mybatis的CRUD 之 保存(在上面回顾代码的项目基础上)
- 在UserDao 持久层接口中编写 保存用户信息的方法 saveUser(User user);
void saveUser(User user);
- 在UserDao.xml映射配置文件中编写对应的 insert 标签 使用 parameterType 指定参数类型, 并编写 sql 语句
insert into user (username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})
- 在测试类中编写对应的测试方法 : 方法中已经将 获取UserDao代理对象的代码抽取到了 测试方法执行之前的方法中。
@Test
public void testSaveUser() {
User user = new User();
user.setUsername("王晓华");
user.setBirthday(new Date());
// 注意这里的字符个数应该与数据库对应
user.setSex("男");
user.setAddress("重庆市巴南区");
// 抽取 获取userDao代理对象的过程 到 测试方法执行之前 , 将释放资源的代码统一写到测试方法执行之后
userDao.saveUser(user);
}
- 抽取获取UserDao代理对象代码 :
// 在测试类中定义如下属性(成员变量)
private InputStream in;
private UserDao userDao;
private SqlSession sqlSession;
// 测试类中定义如下方法
/**
* @Before 在测试方法执行之前执行
*/
@Before
public void init() throws IOException {
in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
sqlSession = factory.openSession();
userDao = sqlSession.getMapper(UserDao.class);
}
/**
* @After 在测试方法执行之后执行
*/
@After
public void destroy() {
// 需要提交事务
// sqlSession.commit();
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (sqlSession != null) {
sqlSession.close();
}
}
- 需要注意的是,这里需要手动提交事务:
- 在测试方法执行之后释放资源之前进行事务的提交即可 :
2.2 MyBatis CRUD 之 修改 和 删除
2.2.1 修改操作
- 在UserDao持久层接口中编写修改方法
// 在UserDao 持久层接口中编写修改方法
/**
* 更新用户信息
* @param user
*/
void updateUser(User user);
- 在UserDao.xml映射配置文件中使用update标签 并使用parameterType属性指定参数类型。编写更新的sql
update user set username = #{username} , birthday = #{birthday} , sex = #{sex} ,
address = #{address} where id = #{id}
- 在测试类中编写测试方法测试更新操作,更新操作也是需要进行手动提交事务操作
/**
* 修改
*/
@Test
public void testUpdateUser() {
User user = new User();
user.setId(50);
user.setUsername("mybatis update");
user.setBirthday(new Date());
user.setAddress("重庆市渝北区");
user.setSex("女");
userDao.updateUser(user);
}
2.2.2 删除操作
- 在UserDao持久层接口中编写删除方法
/**
* 删除用户信息
* @param userId
*/
void deleteUser(int userId) ;
- 在UserDao.xml映射配置文件中使用delete标签编写sql语句,并使用parameterType设置传递的参数类型这里的 parameterType 的值可以为 int 、 INT 、INTEGER 、 Integer、java.lang.Integer。sql语句 : id = #{由于传递的参数只有一个,所以这里的名称可以随意}
delete from user where id = #{uid}
- 在测试类中编写测试方法进行删除测试
/**
* 删除
*/
@Test
public void testDeleteUser() {
userDao.deleteUser(51);
}
2.3 查询一个和模糊查询
2.3.1 查询一个 (根据id查询一个)
- 在UserDao持久层接口中编写方法。
/**
* 根据id查询用户信息
* @param userId
* @return
*/
User selectById(int userId);
- 在UserDao.xml映射配置文件中使用select标签,并使用parameterType 执行参数类型 , 使用resultType='返回值全限定类名'指定返回值类型
- 在测试类中编写测试方法进行测试
/**
* 根据id查询用户信息
*/
@Test
public void testSelectById() {
User user = userDao.selectById(50);
System.out.println(user);
}
2.3.2 根据用户名进行模糊查询
- 在UserDao持久层接口中编写进行模糊查询的方法
/**
* 根据用户名进行模糊查询
* @param username
* @return
*/
List selectByUsername(String username);
- 在UserDao.xml映射配置文件中使用select标签,并使用parameterType 执行参数类型 , 使用resultType='返回值全限定类名'指定返回值类型
- 在测试类中编写测试方法
/**
* 根据username进行模糊查询
*/
@Test
public void testSelectByUsername() {
List users = userDao.selectByUsername("%王%");
for (User user : users) {
System.out.println(user);
}
}
2.4 查询返回一行一列 和 占位符分析
2.4.1 查询返回数据总条数
- 在UserDao持久层接口中编写查询数据总条数的方法
/**
* 查询数据总条数
* @return
*/
int selectTotal();
- 在UserDao.xml映射配置文件中使用select标签 编写sql语句 ,并使用resultType='' 指定返回值类型
- 在测试类中编写测试方法进行测试
/**
* 查询数据总条数
*/
@Test
public void testSelectTotal() {
int total = userDao.selectTotal();
System.out.println("数据总条数: " + total);
}
2.4.2 模糊查询占位符细节
- 可以使用 如下方式代替模糊查询传递参数时需要写上%%;
/**
* 根据username进行模糊查询
*/
@Test
public void testSelectByUsername() {
//List users = userDao.selectByUsername("%王%");
List users = userDao.selectByUsername("王");
for (User user : users) {
System.out.println(user);
}
}
- 进行模糊查询时占位符细节分析:
2.4.3 保存操作的细节
- 保存的时候由于主键自增长的原因,我们是不知道保存时的id的。但是如果我们需要得到当前保存数据的id,可以通过以下的配置
-- 在数据库中插入一条数据并返回 此时插入数据的id
INSERT INTO USER(username,address,sex,birthday) VALUES('testId','重庆市','男','2020-08-30');
SELECT LAST_INSERT_ID();
select LAST_INSERT_ID();
insert into user (username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})
3. MyBatis的参数深入
3.1 OGNL 表达式
OGNL : Object Graphic Navigation Language 对象图导航语言;
作用 : 它是通过对象的取值方法来获取数据 。在写法上将get省略掉;
案例 : 在获取用户名称的时候 , 类中的写法 user.getUsername(); OGNL表达式的写法:user.username;
Mybatis中为什么能直接写username,而不是user.username。因为在parameterType中已经提供了属性所属的类,所以此时不需要写对象名而直接写属性名称。
3.2 使用实体的包装对象作为查询条件
- 定义一个实体的包装类对象QueryVo作为查询条件
/**
* 实体包装类对象
*/
public class QueryVo {
private User user;
// 省略 setter 和 getter 方法
}
- 在UserDao持久层接口中编写根据包装类对象进行查询的方法;
- 在UserDao.xml映射配置文件中使用select编写查询的语句 ,注意在占位符中写的参数
- 在测试类中编写方法进行测试
/**
* 根据包装类对象进行查询
*/
@Test
public void testSelectByVo() {
User user = new User();
user.setUsername("%王%");
QueryVo vo = new QueryVo();
vo.setUser(user);
List users = userDao.selectByVo(vo);
for (User u : users) {
System.out.println(u);
}
}
3.3 实体类属性名称和数据库列名不一致
会出现报错的情况。 这时修改映射配置文件中的属性与实体类对应,增删改操作是可以使用的。但是注意查询操作的时候,将封装不进去了。
修改实体类的属性名称如下:
/**
* User实体类
*/
public class User implements Serializable {
private Integer userId;
private String userName;
private Date userBirthday;
private String userSex;
private String userAddress;
// 省略setter 和 getter方法
}
- 在修改映射配置文件中实体类属性之后,添加和修改操作恢复正常,但是查询操作就值得注意。因为返回的结果集将封装不上。但是userName列比较特殊可以封装上,这是因为在windows下MySQL数据库列名是不区分大小写的。但是在linux操作系统下的MySQL是严格区分大小写的。
3.4 解决实体类属性与数据库列名称不对应的问题
3.4.1 方式一 :起别名
- 通过起别名的方式使数据库列名与实体类属性对应上 。
3.4.2 方式二 : 采用配置的方式
- 使用resultMap标签,定义实体类属性与数据库列名之间的配置映射关系。
- 在 select 标签中 使用resultMap 属性设置使用的resultMap 。
3.5 案例地址
- 案例码云地址 : https://gitee.com/lpzzzz/mybatis_demo_-crud_04
4. 自定义Dao实现类
- 创建新项目 , 复制上面的项目将实体类属性改为与数据库列名一致,删除以封装对象作为查询条件的方法。
4.1 使用自定义实现类的方式 实现 查询所有
- 编写 UserDao接口的实现类 UserDaoImpl.java; 实现其所有的方法 , 并使用构造方法的方式初始化一个SqlSessionFactory对象;
public class UserDaoImpl implements UserDao {
// 需要使用构造函数创建一个SqlSessionFactory 对象
private SqlSessionFactory factory;
public UserDaoImpl(SqlSessionFactory factory) {
this.factory = factory;
}
/**
* 查询所有
*
* @return
*/
public List findAll() {
// 获取一个sqlSession对象
SqlSession session = factory.openSession();
List users = session.selectList("com.lyp.dao.UserDao.findAll");
session.close();
return users;
}
}
- 修改测试类中的配置
/**
* mybatis回顾 测试类
*/
public class MybatisLookBackTest {
private InputStream in;
private UserDao userDao;
/**
* @Before 在测试方法执行之前执行
*/
@Before
public void init() throws IOException {
in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
userDao = new UserDaoImpl(factory);
}
/**
* @After 在测试方法执行之后执行
*/
@After
public void destroy() {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 查询所有
*
* @throws IOException
*/
@Test
public void testSelectList() throws IOException {
List users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
}
}
4.2 使用自定义实现类的方式 实现 保存数据
- 在UserDao实现类 UserDaoImpl 中实现 保存的的方法 saveUser。
/**
* 保存
* @param user
*/
public void saveUser(User user) {
// 获取一个sqlSession对象
SqlSession session = factory.openSession();
session.insert("com.lyp.dao.UserDao.saveUser", user);
session.commit();
}
4.3 使用自定义实现类的方式 实现 修改数据
- 在UserDao实现类UserDaoImpl中实现 修改方法 updateUser。
public void updateUser(User user) {
// 获取一个sqlSession对象
SqlSession session = factory.openSession();
session.update("com.lyp.dao.UserDao.updateUser", user);
session.commit();
}
4.4 使用自定义实现类的方式 实现 删除数据
- 在UserDao实现类UserDaoImpl中实现 删除方法 deleteUser。
public void deleteUser(int userId) {
// 获取一个sqlSession对象
SqlSession session = factory.openSession();
session.update("com.lyp.dao.UserDao.deleteUser", userId);
session.commit();
}
4.5 使用自定义实现类的方式 实现 根据id查询
- 在UserDao实现类UserDaoImpl中实现 查询一个(根据id查询)的方法 selectById。
/**
* 查询一个(根据id进行查询)
* @param userId
* @return
*/
public User selectById(int userId) {
// 获取一个sqlSession对象
SqlSession session = factory.openSession();
User user = session.selectOne("com.lyp.dao.UserDao.selectById", userId);
session.commit();
return user;
}
4.6 使用自定义实现类的方式 实现 根据用户名进行模糊查询
- 在UserDao实现类UserDaoImpl中实现 根据用户名进行模糊查询 的方法 selectByUsername。
/**
* 根据username进行模糊查询
* @param username
* @return
*/
public List selectByUsername(String username) {
// 获取一个sqlSession对象
SqlSession session = factory.openSession();
return session.selectList("com.lyp.dao.UserDao.selectByUsername",username);
}
4.7 使用自定义实现类的方式 实现 查询数据条数
/**
* 查询当前数据库中数据条数
* @return
*/
public int selectTotal() {
// 获取一个sqlSession对象
SqlSession session = factory.openSession();
return session.selectOne("com.lyp.dao.UserDao.selectTotal");
}
5. 使用Dao实现类方式的执行过程分析
5.1 断点小技巧
6. properties 标签的使用及细节
在使用代理dao的方式的项目 (mybatis_demo_CRUD_04) 中进行配置。
码云地址 : https://gitee.com/lpzzzz/mybatis_demo_-crud_04
6.1 在标签中直接配置数据库连接信息
- 将原来的数据库配置信息复制到 properties 标签中 ,然后使用${} 使用属性名称进行引用。
6.2 使用 properties配置文件的方式
- 先再类路径 resources 目录下创建 一个编写数据库配置信息的properties配置文件。内容如下:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=xxxx
- 在properties标签上使用,resource属性配置配置文件位置及名称 :
- 和标签内配置数据库连接信息一样,使用${} 获取到数据库的连接信息:
6.3 在引用properties 配置文件两种方式
6.3.1 使用resource 属性
- 使用resource属性是使用相对路径读取的类路径下的文件。
6.3.2 使用 url 属性
- URL: Uniform Resource Locator 统一资源定位符,它是可以标识一个资源的位置;
- 例: localhost:9999/user/userInfo?id=100
- URI: Uniform Resource Identifier 统一资源标识符,它是可以在应用中唯一定位一个资源的位置。
- 例:/user/userInfo?id=100
-
在配置中使用 url 属性配置配置文件的位置:
- properties标签配置的位置:
7. TypeAliases 和 package 标签的使用
- 使用typeAliases 标签 中的typeAlias标签 配置 别名。只能配置domain中类的别名。type属性指定的是实体类的全限定类名,alias属性上指定的是别名,指定之后就不在区分大小写。
- 使用 typeAliases 标签 中的 packge 标签配置别名 , 用于指定要配置别名的包,当指定后,该包下的实体类都会注册别名并且类名就是别名,并且不在区分大小写。
- 在mappers 标签中也有一个package的标签。该标签是用于指定dao接口所在的包。当指定完成之后就不需要再写 mapper 以及 resource 和class了。
- 上面几个标签的使用如下图 :