mybatis学习日记
1.什么是框架
框架是软件开发中的一套解决方案,不同的框架解决不同的问题
2.三层架构
表现层:展示数据
业务层:处理业务需求
持久层:与数据库交互
3.持久层解决技术
-
JDBC技术(JDBC是一种规范)
-
- Apache的DBUtils(工具类):和Spring的JdbaTemplate很像,也是对Jdbc的简单封装
4.mybatis入门
4.1.mybatis环境搭建
第一步:创建maven工程并导入坐标
打jar包
<dependencies> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.5</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> <scope>runtime</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency> </dependencies>
第二步:创建实体类和dao的接口
public interface IUserDao { List<User> findAll();
}
第三步:创建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> <!-- 配置 mybatis 的环境 --> <environments default="mysql"> <!-- 配置 mysql 的环境 --> <environment id="mysql"> <!-- 配置事务的类型 --> <transactionManager type="JDBC"></transactionManager> <!-- 配置连接数据库的信息:用的是数据源(连接池) --> <dataSource type="POOLED"> <!-- 配置连接数据库的4个基本信息 --> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/数据库名"/> <property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource> </environment> </environments> <!-- 告知 mybatis 映射配置文件的位置 --> <mappers> <mapper resource="com/itheima/dao/IUserDao.xml"/> </mappers> </configuration>
第四步:创建映射配置文件
<?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.itheima.dao.IUserDao"> <!-- 配置查询所有操作 --> <select id="findAll" resultType="com.itheima.domain.User">
select * from user
</select>
4.2.环境搭建注意事项
第一个:mybatis映射配置文件位置必须和dao接口的包结构相同
第二个:映射配置文件的mapper标签namespace属性的取值必须是dao接口的全限定类名,表示是哪个dao接口
第三个:映射配置文件的操作配置,id属性的取值必须是dao接口的方法名
第四个:映射配置文件中,resultType是将执行完的代码封装到哪个实体类中后边接的是实体类的全限定类名
4.3.编写测试类
public class MybatisTest { public static void main(String[] args)throws Exception { //1.读取配置文件 ,生成字节输入流 InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.创建 SqlSessionFactory 的构建者对象 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //3.使用构建者创建工厂对象 SqlSessionFactory factory = builder.build(in); //4.使用 SqlSessionFactory 生产 SqlSession 对象 SqlSession sqlSession = factory.openSession(); //5.使用 SqlSession 创建 dao 接口的代理对象 IUserDao userDao = sqlSession .getMapper(IUserDao.class); //6.使用代理对象执行查询所有方法 List<User> users = userDao.findAll(); for(User user : users) { System.out.println(user); }
//7.释放资源 session.close(); in.close(); } }
图:mybatis分析
5.基于注解开发
5.1.移除映射配置文件
5.2.在持久层接口中添加注解,指定sql语句
public interface IUserDao { @Select("select * from user") List<User> findAll(); }
5.3.修改SqlMapConfig.xml主配置文件(使用class属性指定dao接口的全限定类名,之前是resource属性指定的映射配置文件位置)
<!-- 告知 mybatis 映射配置的位置 -->
<mappers>
<mapper class="com.itheima.dao.IUserDao"/>
</mappers>
6.查询所有的分析
mybatis读取配置文件用到了dom4j(读取xml的技术)的技术
在主配置文件中配置的连接数据库的4个基本信息:创建了Connection对象
主配置文件中的<mappers>标签,能够有映射配置文件信息
配置文件中:有了可执行的sql语句,就可以获取PrepareStatement对象,还能知道封装到的类
代理对象的创建
Proxy有一个方法叫做ProxyInstance,这个方法有三个参数
7.mybatis的CRUD操作
7.1.保存操作
7.1.1在持久层接口中添加保存方法
/** *保存用户 @param user @return 影响数据库记录的行数 */ int saveUser(User user);
7.1.2在配置文件中配置
<!-- 保存用户-->
<insert id="saveUser" parameterType="com.itheima.domain.User">
insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>
细节:
parameterType 属性:
代表参数的类型,因为我们要传入的是一个类的对象,所以类型就写类的全名称。
sql 语句中使用#{}字符:
它代表占位符,相当于原来 jdbc 部分所学的?,都是用于执行语句时替换实际的数据。
具体的数据是由#{}里面的内容决定的。
#{}中内容的写法:
由于我们保存方法的参数是 一个 User 对象,此处要写 User 对象中的属性名称。它用的是 ognl 表达式。
ognl 表达式:
它是 apache 提供的一种表达式语言,全称是: Object Graphic Navigation Language 对象图导航语言
它是按照一定的语法格式来获取数据的。
语法格式就是使用 #{对象.对象}的方式
#{user.username}它会先去找 user 对象,然后在 user 对象中找到 username 属性,并调用 getUsername()方法把值取出来。但是我们在 parameterType 属性上指定了实体类名称,所以可以省略 user. 而直接写 username
7.1.3测试类
private InputStream in; private SqlSession sqlSession; private IUserDao userDao; private SqlSessionFactory factory; @Before //用于在测试方法执行之前执行 public void init() throws Exception{ //1.读取配置文件 ,生成字节输入流 in = Resources.getResourceAsStream("SqlMapConfig.xml"); //2.创建 SqlSessionFactory 的构建者对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); //3.使用构建者创建工厂对象 factory = builder.build(in); //4.使用 SqlSessionFactory 生产 SqlSession 对象 sqlSession = factory.openSession(); //5.使用 SqlSession 创建 dao 接口的代理对象 userDao = sqlSession .getMapper(IUserDao.class); } @After public void destroy()throws Exception{ //提交事务 sqlSession .commit(); //7.释放资源 sqlSession .close(); in.close(); } @Test public void testSave(){ User user = new User(); user.setUsername("modify User property"); user.setAddress("北京市顺义区"); user.setSex("男"); user.setBirthday(new Date()); System.out.println("保存操作之前:"+user); //6.执行保存方法 userDao.saveUser(user); System.out.println("保存操作之后:"+user); }
7.2.更新
7.2.1在持久层添加更新方法
/** *更新用户 @param user @return 影响数据库记录的行数 */ int updateUser(User user);
7.2.2在配置文件中配置
<!-- 更新用户 --> <update id="updateUser" parameterType="com.itheima.domain.User"> update user set username=#{username},birthday=#{birthday},sex=#{sex}, address=#{address} where id=#{id} </update>
7.2.3测试类
@Test public void testUpdateUser()throws Exception{ User user=new User(); user.setrId(50); user.setrUsername(“智障”); user.setrAddress(“吉林省长春市”); user.setrSex("女"); user.setrBirthday(new Date()); //执行保存方法 userDao.updateUser(User);
}
7.3删除用户
7.3.1在持久层添加删除方法
/** *根据 id 删除用户 @param userId @return */ int deleteUser(Integer userId); //注意,删除时不用传入user对象,根据id删除
7.3.2在配置文件中配置
<!-- 删除用户 --> <delete id="deleteUser" parameterType="java.lang.Integer"> delete from user where id = #{uid} </delete>
注意:此处#{} 中的内容可以随便写,由于数据类型是基本类型,所以此处可以随意写。
注意parameterType参数类型
7.3.3测试类
@Test public void testDeleteUser() throws Exception { //执行操作 userDao.deleteUser(52); }
7.4查询一个
7.4.1在持久层添加查询一个方法
/** 根据 id 查询 param userId return */ User findById(Integer userId); // 返回的是一个user对象
7.4.2在配置文件中配置
<!-- 根据 id 查询 -->
<select id="findById" resultType="com.itheima.domain.User" parameterType="int"> select * from user where id = #{uid} </select>
细节:
此处是user类型,所以要写resultType 属性
resultType 属性:
用于指定结果集的类型。
parameterType 属性:
用于指定传入参数的类型。
#{}中内容的写法:
由于数据类型是基本类型,所以此处可以随意写。
7.4.3测试类
@Test public void testFindOne() { //执行操作 User user = userDao.findById(41); System.out.println(user); }
7.5根据名称模糊查询
7.5.1.在持久层添加模糊查询方法
/** *根据名称模糊查询 *@param username *@return */ List<User> findByName(String username); //注意,返回的应该是一个List集合,你想吧,不可能那么巧合模糊查询只有一个结果啊
7.5.2.在配置文件中配置
<!-- 根据名称模糊查询 -->
<select id="findByName" resultType="com.itheima.domain.User" parameterType="String">
select * from user where username like #{username}
</select>
注意:List集合这块传入了User对象,所以还是应该有resultType属性
7.5.3.测试类中加入模糊查询
@Test public void testFindByName(){ //执行查询一个方法 List<User> users = userDao.findByName("%王%"); for(User user : users){ System.out.println(user); } }
7.6.模糊查询的另一种方式
第一步:在持久层添加模糊查询方法
/** *根据名称模糊查询 *@param username *@return */ List<User> findByName(String username);
第二步:在配置文件中的修改sql语句使用模糊查询
<select id="findByName" parameterType="string" resultType="com.itheima.domain.User">
select * from user where username like'%${value}%'
</select>
注意:如果用这种模糊查询的写法,那么${value}的写 法就是固定的,不能写成其它名字
第三步:测试类
@Test public void testFindByName(){ //执行模糊查询方法 List<User> users = userDao.findByName("王"); for(User user : users){ System.out.println(user); } }
注意:此时测试类中的王不用加匹配符%了
7.7两种模糊查询比较
在测试类中使用模糊查询更好,不推荐在配置文件中修改sql语句使用模糊查询
原因:一个是使用statement对象的字符串拼接sql
另一个是使用preparedStatement的参数占位符,当然是使用这个啊
7.8.查询时使用聚合函数查询总记录条数
7.8.1.在持久层添加查询总记录条数方法
/** *查询总记录条数 *@return */ int findTotal()
7.8.2.在配置文件中配置
<select id="findTotal" resultType="int">
select count(*) from user;
</select>
7.8.3.测试类
@Test public void testFindTotal() throws Exception { //执行操作 int count=userDao.findTotal(); System.out.println(count); }