Mybatis的基础环境搭建
- [1] 创建一个不需要任何骨架的maven项目
- [2] 在pom中导入需要的jar包坐标
- [3] 在resources中创建一个SqlConFig.xml主配置文件
第一个value后面写的是想要连接的数据库的驱动
第二个value后面写的想要连接的数据库名称
第三第四行是连接数据库的用户名和密码
mapper标签中设置想要加载的接口子配置文件
- [4] 在resources资源目录下创建一个mapper文件夹,文件夹存放各个接口的配置文件
mapper中写入加载的接口路径 - [5] 将log4j配置文件导入resources资源目录下
框架中的几个主要对象
//将主配置文件以流的形式加载到内存中
InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
//得到一个工厂生产者对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//生产一个数据库执行对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//用动态代理的方式将接口加载
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
- [1] SqlSession对象
回顾原生jdbc操作:加载数据库驱动,创建Connection链接,得到预编译的操作对象,执行数据库操作得到结果集ResultSet,处理器结果集得到User对象,释放资源。
Mybatis框架对以上操作进行了封装。 Mybatis真正操作数据库的对象就是SqlSession。
由于Connection对象线程不安全,所以SqlSession也线程不安全。
由于SqlSession线程不安全,所有需要反复的创建和销毁。 由于对象要不断的创建和销毁,要用工厂模式。 - [2] SqlSessionFactory对象
专门负责创建SqlSession对象。 - [3] SqlSessionFactoryBuilder对象
把配置文件中的数据解析出来,并放到一个对象中,供SqlSessionFactory使用。 - [4] Resources对象
把配置文件变成流。
使用mybatis框架映射方式进行单表的增删改
//接口
public interface UserMapper {
//添加一条用户数据信息到数据库中
public void saveUser(User user);
//根据id更新一条用户的信息
public void updateUser(User user);
//根据用户id删除一条数据库中的记录
public void deleteUser(Integer id);
}
//测试方法
//向数据库添加一条新的记录
@Test
public void saveUser(){
//用动态代理的方式将接口加载
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//创建一个实例对象
User user = new User();
user.setUsername("舒克");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("黑马程序员");
mapper.saveUser(user);
}
//根据用户id更改用户信息
@Test
public void updateUser(){
//用动态代理的方式将接口加载
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//创建一个实例对象
User user = new User();
user.setUsername("贝塔");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("黑马程序员");
user.setId(54);
mapper.updateUser(user);
}
//根据用户id删除一条数据库中的记录
@Test
public void deleteUser(){
//用动态代理的方式将接口加载
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//创建一个实例对象
User user = new User();
mapper.deleteUser(54);
}
<!-- 配置文件 -->
<!-- namespace的当前mapper的唯一标识,一个类对象对应一个唯一的标识 -->
<!--
insert 标签是用来做添加操作的
id 是当前想要执行的sql语句的唯一标识
parameterType 是当前参数的类型
#{} 是占位符,完全等同于?号占位符
如果想要传递的参数是对象类型的,#{}中写的是对象的属性名
-->
<!-- 添加一条有用户信息到数据库中 -->
<insert id="saveUser" parameterType="user">
insert into user (username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
</insert>
<!-- 根据id更新一条数据库中的用户数据信息 -->
<update id="updateUser" parameterType="user">
update user set username=#{username},
birthday=#{birthday},
sex=#{sex},
address=#{address}
where id = #{id}
</update>
<!-- 根据用户id删除一条数据库中的记录 -->
<delete id="deleteUser" parameterType="int">
delete from user where id=#{id}
</delete>
总结: 从以上三条单表的增删查改中可以发现,执行sql语句的标签中,id属性后写的是映射的接口中的抽象方法名称,parameterType属性后写的是接口抽象方法向数据库传递的参数(简单来说也就是占位符所代表的数据类型)
使用mybatis框架映射方式进行单表的数据查询
//接口
//查询用户表中的所有数据
public List<User> findAll();
//根据id查询对应的用户信息,列名使用别名
public User findById(Integer id);
//测试类
//查询用户表中的所有数据
@Test
public void findAll() {
//用动态代理的方式将接口加载
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//创建一个实例对象
User user = new User();
List<User> all = mapper.findAll();
System.out.println(all);
}
//根据id查询对应的用户信息,列名使用别名
@Test
public void findById() {
//用动态代理的方式将接口加载
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User byId = mapper.findById(53);
System.out.println(byId);
}
<!-- 配置文件 -->
<!-- 查询用户表中的所有数据 -->
<select id="findAll" resultType="user">
select * from user
</select>
<!-- 根据id查询对应的用户信息,列名使用别名 -->
<!-- id为自己制定的名称(跟下面select标签中的resultMap属性相对应)
type是返回的map集合中封装的对象名称 -->
<resultMap id="userMap" type="user">
<!-- id标签中的property为主键名称,只是一个规范,也可以都写成result标签,
column标签中写入的是给对应列名起得别名-->
<id property="id" column="_id"/>
<result property="username" column="_username"/>
<result property="birthday" column="_birthday"/>
<result property="sex" column="_sex"/>
<result property="address" column="_address"/>
</resultMap>
<select id="findById" parameterType="int" resultMap="userMap">
select id _id,username _username,birthday _birthday,sex _sex,address _address from user where id=#{id}
</select>
**总结:**当执行查询操作的时候,可以使用resultType属性可以使用resultMap属性,这两个属性后填写的都是查询出来对象的名称.但是使用resultType属性必须要保证查询列名与数据库表中列名的一致性.而resultMap可以通过标签给查询列名设置别名,在resultMap标签中的id属性与select标签中的sersltMap属性是对应的.
使用mybatis框架映射方式进行有多个参数的单表数据查询
//接口
//根据id和用户名查询数据库中的用户信息
public User findByIdAndUsername(Integer id,String username);
//测试方法
//根据id和用户名查询数据库中的用户信息
@Test
public void findByIdAndUsername() {
//用动态代理的方式将接口加载
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//执行查询语句并返回结果
User u = mapper.findByIdAndUsername(53, "乐");
System.out.println(u);
}
//映射文件
<!-- 根据id和用户名查询数据库中的用户信息 -->
<select id="findByIdAndUsername" resultType="user">
select * from user where id=#{id} and username=#{username}
</select>
尝试以上返回后idea却给出了报错信息
根据报错信息,我们尝试写入另外的两种形式
成功获取到了用户的信息
实在不想用以上的方式,又想用占位符可以采取使用Param注解的方式
//接口
//使用@Param注解的方式根据id和用户名查询数据库中的用户信息
public User findByIdAndUsernameParam(@Param("id") Integer id, @Param("username") String username);
<!-- 配置文件 -->
<!-- 使用@Param注解的方式根据id和用户名查询数据库中的用户信息 -->
<select id="findByIdAndUsernameParam" resultType="user">
select * from user where id=#{id} and username=#{username}
</select>
//测试类
//使用@Param注解的方式根据id和用户名查询数据库中的用户信息
@Test
public void findByIdAndUsernameParam() {
//用动态代理的方式将接口加载
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//执行查询语句并返回结果
User u = mapper.findByIdAndUsernameParam(46, "老王");
System.out.println(u);
}
使用mybatis框架映射方式进行单表模糊查询(常用的两种方式)
//接口
//模糊查询(方式一)
public List<User> findByUsername(String username);
//模糊查询(方式二)
public List<User> findByUsernameTwo(String username);
<!-- 模糊查询 -->
<select id="findByUsername" parameterType="String" resultType="user">
select * from user where username like #{username}
</select>
<!-- 模糊查询 -->
<select id="findByUsernameTwo" parameterType="String" resultType="user">
select * from user where username like '%${value}%'
</select>
//模糊查询(方式一)
@Test
public void findByUsername() {
//用动态代理的方式将接口加载
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//执行查询语句并返回结果
List<User> list = mapper.findByUsername("老王");
System.out.println(list);
}
//模糊查询(方式二)
@Test
public void findByUsernameTwo() {
//用动态代理的方式将接口加载
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//执行查询语句并返回结果
List<User> list = mapper.findByUsernameTwo("老王");
System.out.println(list);
}
获取新添加数据的主键值
使用场景: 级联保存,保存主表数据的同时保存从表数据,从表是包含外键的表,外键来自于主表的主键,这时就需在主表数据保存完成后,得到当前新增数据的主键值。
通过我们第一次使用的添加方法查看是否能获取到主键的值
@Test
public void saveUser() {
//用动态代理的方式将接口加载
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//创建一个实例对象
User user = new User();
user.setUsername("舒克");
user.setBirthday(new Date());
user.setSex("男");
user.setAddress("黑马程序员");
mapper.saveUser(user);
System.out.println("---------"+user.getId());
}
我们可以看见获取到的值为空
通过修改映射文件,尝试是否能获取到新添加数据在表中的主键值
<!-- 添加一条有用户信息到数据库中 -->
<!-- 其中的useGeneratedKeys="true" 表示在执行完添加操作以后,获取到新添加数据的主键值
keyProperty="id" 表示 当获取新增数据的主键值以后赋值给对象中的那个属性
-->
<insert id="saveUser" parameterType="user" useGeneratedKeys="true" keyProperty="id">
insert into user (username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address})
</insert>
在修改完配置文件一会,再次运行,尝试是否可以获取到新增数据在表中的主键值
再次运行后我们发现可以成功获取值,可是发现了一个新的问题,在Oracle数据库中主键是没有自增的
功能的,所以这种解决方式并不能保证代码的通用性
动态sql之if判断
//接口
//根据用户名获取id进行数据查询
public List<User> findByUsernameOrId(User user);
<!-- 根据用户名获取id进行数据查询 -->
<!-- where标签表示where关键字,并且会在需要的时候自动去掉and
if标签表示java中的if关键字,用于判断条件,相当于java中的多重if
-->
<select id="findByUsernameOrId" parameterType="user" resultType="user">
select * from user
<where>
<if test="id != null">
and id=#{id}
</if>
<if test="username != null and username != ''">
and username=#{username}
</if>
</where>
</select>
//测试方法
//根据用户名获取id进行数据查询
@Test
public void findByUsernameOrId(){
//用动态代理的方式将接口加载
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = new User();
user.setUsername("老王");
//执行查询语句并返回结果
List<User> list = mapper.findByUsernameOrId(user);
System.out.println(list);
}
使用mybatis框架映射方式进行单表查询是一次传递多个参数
//接口
//一次查询多个指定id的用户数据
public List<User> findByManyId(@Param("ids") List<Integer> ids);
<!-- 配置文件 -->
<!-- 一次查询多个指定id的用户数据 -->
<select id="findByManyId" parameterType="int" resultType="user">
select * from user
<where>
<foreach collection="ids" item="id" open="id IN( " separator="," close=")" >
#{id}
</foreach>
</where>
</select>
```java
//测试方法
//一次查询多个指定id的用户数据
@Test
public void findByManyId(){
//用动态代理的方式将接口加载
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<Integer> ids = new ArrayList<Integer>();
ids.add(51);
ids.add(52);
ids.add(53);
List<User> byManyId = mapper.findByManyId(ids);
System.out.println(byManyId);
}
使用mybatis框架映射方式进行双表关联查询
//接口
//双表关联查询所有账户下的所有用户信息
public List<Account> findAllTwo();
//配置文件
<!-- <resultMap id="accountMap" type="account"> 不推荐写法
<id property="id" column="id"/>
<result property="money" column="money"/>
<result property="user.id" column="uid"/>
<result property="user.username" column="username"/>
<result property="user.birthday" column="birthday"/>
<result property="user.sex" column="sex"/>
<result property="user.address" column="address"/>
</resultMap>-->
<!-- 推荐写法 -->
<resultMap id="accountMap" type="account">
<id property="id" column="id"/>
<result property="money" column="money"/>
<association property="user" javaType="user">
<result property="id" column="uid"/>
<result property="username" column="username"/>
<result property="birthday" column="birthday"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
</association>
</resultMap>
<select id="findAllTwo" resultMap="accountMap">
select * from account a left join user u on a.uid=u.id
</select>
//测试方法
//双表关联查询所有账户下的所有用户信息
@Test
public void findAllTwo(){
//用动态代理的方式将接口加载
AccountMapper mapper = sqlSession.getMapper(AccountMapper.class);
List<Account> allTwo = mapper.findAllTwo();
System.out.println(allTwo);
}
使用mybatis框架嵌套查询<重点>☆☆☆
概念:一个查询中嵌套了另外一个查询,优势是把原本一次多表联查的操作,拆分成多个单表查询。