文章目录
1.基于代理Dao的CRUD操作
1.1根据ID进行查询
涉及到对数据库的操作,所使用的表还是之前已经创建好的User表。
- 在持久层接口添加 getUserById 方法。
public interface IUserDao {
/**
* 查找所有用户
* @return
*/
List<User> findAll();
/**
* 根据id查找用户
* @param id
* @return
*/
User getUserById(Integer id);
- 在用户的映射配置文件IUserDao.xml 中进行配置。
<?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">
<mapper namespace="com.zut.dao.IUserDao">
<!-- 查找所用 -->
<select id="findAll" resultType="com.zut.domain.User">
select * from user
</select>
<!-- 根据id查找用户 -->
<select id="getUserById" parameterType="java.lang.Integer" resultType="com.zut.domain.User">
select * from user where id=#{aa}
</select>
</mapper>
- 这里的 parameterType 用于指定传入的参数类型。
- sql语句中使用的 #{ }
则代表一个占位符,相当于JDBC中的?,用于执行语句时替换实际的数据。具体的数据内容由#{}里面的内容决定。- 因为这里传入的参数为基本类型,所以此处可以随意写,任何内容均可。
- 在测试类中添加测试
public class mybatistest {
private IUserDao iUserDao;
private SqlSession session;
//初始化
@Before
public void init() throws Exception{
//1.读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3.使用工厂生产sqlSessino对象
session = factory.openSession();
//4.使用SqlSession创建Dao的代理对象
iUserDao = session.getMapper(IUserDao.class);
}
@After
public void destory(){
session.commit();
//释放资源
session.close();
}
/**
* 测试根据id获取用户
*/
@Test
public void getUserById(){
User user = iUserDao.getUserById(45);
System.out.println(user);
}
}
测试类中 destory 方法中写了一句代码:session.commit(),它的作用是进行事务的手动提交。如果要设置自动提交。可以在 openSession方法中设置参数true。
当然此处我们可以不写这一句代码,因为这里测试的是查询方法。
1.2 保存操作
- 同样,第一步还是在持久层接口中添加方法。
/**
* 保存操作
*/
void saveUser(User user);
- 在用户的映射配置文件IUserDao.xml 中进行配置。
<!-- 保存操作 -->
<insert id="saveUser" parameterType="com.zut.domain.User">
insert into user(username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})
</insert>
这里的sql语句中也用到了#{ },但注意,此处括号里的内容不能乱写!!!
它必须和实体类中的属性名进行一一对应,这里实际上是通过实体类的getXxx()方法来拿到具体的值。
- 在测试类中添加测试
public class mybatistest {
private IUserDao iUserDao;
private SqlSession session;
//初始化
@Before
public void init() throws Exception{
//1.读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3.使用工厂生产sqlSessino对象
session = factory.openSession();
//4.使用SqlSession创建Dao的代理对象
iUserDao = session.getMapper(IUserDao.class);
}
@After
public void destory(){
session.commit();
//释放资源
session.close();
}
/**
* 测试保存用户
*/
@Test
public void testsaveUser(){
User u = new User();
u.setUsername("王老五");
u.setBirthday(new Date());
u.setSex("女");
u.setAddress("北京市莲花大道");
System.out.println("保存前:" + u);
iUserDao.saveUser(u);
System.out.println("保存后:" + u);
}
}
注意:这里的session.close一定不能省略,否则会造成保存不成功,因为保存的操作涉及到事务的操作,必须进行事务的提交。
- 扩展操作:新增用户id的返回值
新增用户后,同时还要返回当前新增用户的 id 值,因为 id 是由数据库的自动增长来实现的,所以就相当于我们要在新增后将自动增长 auto_increment 的值返回。
<insert id="saveUser" parameterType="com.zut.domain.User"> <!-- parameterType代表参数类型 -->
<!-- 同时获取id的返回值 -->
<selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
select LAST_INSERT_ID()
</selectKey>
insert into user(username,birthday,sex,address) values (#{username},#{birthday},#{sex},#{address})
<!-- 这里的#{}里面的内容不能乱写,他是User实体类中getXXX()方法的 XXX 此符号是通过get方法拿到值 -->
</insert>
这里使用一个selectKey 标签来获取。
keyProperty 对应实体类中的属性名 。
keyColumn 对应数据库中的属性名 。
order 可以被设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它会首先生成主键,设置 keyProperty 然后执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后再执行 selectKey 中的语句。
1.3 更新操作
- 在持久层中添加方法
/**
* 修改用户
* @param user
*/
void updateUser(User user);
- 在用户的映射配置文件IUserDao.xml 中进行配置。
<update id="updateUser" parameterType="com.zut.domain.User">
update user set username = #{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
</update>
- 在测试类中加入方法
/**
* 测试更新用户
*/
@Test
public void updateUser(){
User u = new User();
u.setId(41);
u.setUsername("李老大");
u.setBirthday(new Date());
u.setSex("女");
u.setAddress("北京市莲花大道");
iUserDao.updateUser(u);
}
1.4 删除操作
- 在持久层中添加方法
/**
* 根据 id 删除用户
* @param userId
* @return
*/
int deleteUser(Integer userId);
- 在用户的映射配置文件IUserDao.xml 中进行配置。
<!-- 删除用户 -->
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id = #{uid}
</delete>
- 在测试类中加入方法
@Test
public void testDeleteUser() throws Exception {
int res = userDao.deleteUser(52);
System.out.println(res);
}
1.5用户模糊查询
- 在持久层中添加方法
/**
* 根据姓名模糊查询多个用户
* @param username
* @return
*/
List<User> listUserByName(String username);
- 在用户的映射配置文件IUserDao.xml 中进行配置。
<select id="listUserByName" parameterType="java.lang.String" resultType="com.zut.domain.User">
select * from user where username like #{name}
</select>
这里虽然返回结果为一个List,但resultType可以写为User,当有多个User时,Mybatis会自动帮我们封装为一个集合。
- 在测试类中加入方法
@Test
public void listUserByName(){
List<User> users = iUserDao.listUserByName("%王%");
for (User user:users){
System.out.println(user);
}
}
执行结果如下:
- 我们在配置文件中没有加入%来作为模糊查询的条件,所以在传入字符串实参时,就需要给定模糊查询的标识%,配置文件中的#{name}也只是一个占位符,所以sql语句中为
?
另一种配置方式:
- 修改用户的映射配置文件IUserDao.xml
<select id="listUserByName" parameterType="java.lang.String" resultType="com.zut.domain.User">
select * from user where username like '%${value}%'
</select>
- 修改测试方法
@Test
public void listUserByName(){
List<User> users = iUserDao.listUserByName("王");
for (User user:users){
System.out.println(user);
}
}
运行结果:
这里我们可以看到将以前的占位符改为了${value},者就是模糊查询的写法,注意!!! ${value}的写法是固定的,不能进行更改。
- #{ } 与 ${ }的区别
- #{ }表示一个占位符
- ${ }表示拼接sql串
1.6 查询使用聚合函数
- 在持久层中添加方法
/**
* 使用聚合函数查询用户总数
* @return
*/
int countUser();
- 在用户的映射配置文件IUserDao.xml 中进行配置。
<select id="countUser" resultType="int">
select count(id) from user
</select>
- 在测试类中加入方法
/**
* 测试查询用户总数
*/
@Test
public void countUser(){
int count = iUserDao.countUser();
System.out.println("用户记录总数为:" + count);
}
2.Mybatis中一些参数的了解
2.1 parameterType配置参数
该属性之前已经简单介绍过,它的取值可以是基本类型、引用类型(例如String),还可以是实体类类型。这里说一下它的注意事项。
- 基本类型和String我们可以直接写类型名称,也可以使用包名、类名的方式。
- 实体类类型只能使用全限定类名。
- 因为Mybatis它自动注册了基本类型和String类型的别名,所以使用时可以不写包名。
而我们自己也可以为我们的实体类注册别名从而不再写包名,这个后面会说到。
2.2 传递pojo对象
- 开发中通过 pojo 传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。
- 编写QueryVo
/**
* 用于封装查询条件
*/
public class QueryVo {
private User user;
//如果还有其他的查询条件,就可以一并封住出来
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
- 在持久层添加方法
/**
* 根据查询条件模糊查询用户
* @param vo
* @return
*/
List<User> listUsersByVo(QueryVo vo);
- 在用户的映射配置文件IUserDao.xml 中进行配置。
<select id="listUsersByVo" parameterType="com.zut.domain.QueryVo" resultType="com.zut.domain.User">
select * from user where username like #{user.username}
</select>
- 测试代码
/**
* 测试根据Vo查询
*/
@Test
public void listUsersByVo(){
QueryVo vo = new QueryVo();
User user = new User();
user.setUsername("%王%");
vo.setUser(user);
List<User> users = iUserDao.listUsersByVo(vo);
for (User user1:users){
System.out.println(user1);
}
}
3.Mybatis输出结果的封装
3.1resultType配置结果类型
- resultType和前面的parameterType类似,它支持基本类型和实体类类型。
- 同时注册过别名的,也可以直接使用别名。
需要注意的是:
当类型为实体类型时,实体类的属性必须和查询语句中的列明保持一致。
- 修改实体类
public class User implements Serializable {
private Integer userId;
private String userName;
private Date userBirthday;
private String userSex;
private String userAddress;
- 测试结果如下
为什么userName有值呢?,这是因为Mysql在windows下不区分大小写。所以userName等同于username.
- 为了解决实体类属性名和数据库列名不一致的情况,有如下的解决办法:
1.在 SQL 语句中为所有列起别名,使别名与实体类属性名一致(执行效率相对高,开发效率低)
<select id="findAll" resultType="com.zut.domain.User">
SELECT id AS userId, username AS userName, birthday AS userBirthday, sex AS userSex, address AS userAddress FROM user
</select>
2.使用resultMap标签建立查询的列名和实体类属性之间的映射关系(执行效率相对低,开发效率高)
<mapper namespace="com.zut.dao.IUserDao">
<!-- 配置 resultMap ,完成实体类与数据库表的映射 -->
<resultMap id="userMap" type="cn.ykf.pojo.User">
<id property="userId" column="id" />
<result property="userName" column="username"/>
<result property="userBirthday" column="birthday"/>
<result property="userAddress" column="address"/>
<result property="userSex" column="sex"/>
</resultMap>
<!-- 配置查询所有用户 -->
<select id="findAll" resultMap="userMap">
SELECT * FROM user
</select>
</mapper>
property代表实体类中的属性名称,column代表列名
4.SqlMapConfig.xml配置文件
4.1配置内容和顺序
注意:配置文件要严格遵守上图的顺序,比如typeAliases标签不能写到settings标签前面,否则会出错。
4.2properties标签
- 在使用 properties 标签配置时,我们可以采用两种方式指定属性配置。
1.采用内部配置的方式
<?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>
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/db_mybatis?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="ljt074517"/>
</properties>
<!--配置环境-->
<environments default="mysql">
<environment id="mysql">
<!-- 配置事务类型 -->
<transactionManager type="JDBC"/>
<!-- 配置数据源(连接池) -->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- 指定映射文件 -->
<mappers>
<mapper resource="com/zut/dao/IUserDao.xml"/>
</mappers>
</configuration>
2.使用resource属性引入外部配置文件(常用)
- 在类路径下编写配置文件 jdbcConfig.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db_mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=ljt074517
- 修改Mybatis配置文件
<!-- 引入外部文件 -->
<properties resource="jdbcConfig.properties"/>
<!--配置环境-->
<environments default="mysql">
<environment id="mysql">
<!-- 配置事务类型 -->
<transactionManager type="JDBC"/>
<!-- 配置数据源(连接池) -->
<dataSource type="POOLED">
<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>
4.3typeAliases标签(类型别名)
前面已经提到过别名这个概念,此标签的作用就是来配置别名
- 当我们要给某个实体类指定别名时,就可以在 SqlMapConfig.xml 中去配置
<!-- 配置别名 -->
<typeAliases>
<typeAlias type="com.zut.domain.User" alias="user"></typeAlias>
</typeAliases>
- type属性用于指定实体类的全限定类名,alias标签用于指定别名。
- 也就是说当我们要用User这个实体类作为parameterType或resultType的类型时,可以直接写为user
- 当我们需要给多个实体类起别名时,可以使用package标签
<!-- 配置别名 -->
<typeAliases>
<package name="com.zut.domain"/>
</typeAliases>
package 标签指定要配置别名的包,当指定之后,该包下的所有实体类都会注册别名,并且别名就是类名,不再区分大小写
- package标签还有另外一个作用:注册指定包下的所有 mapper 接口
<!-- 配置映射信息 -->
<mappers>
<package name="com.zut.dao"/>
</mappers>
- 这样配置后,我们就无需一个个的映射Mapper接口
- 此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。