02Mybatis 实现CRUD

作者: better_future | 来源:发表于2020-04-24 20:55 被阅读0次
使用前面所学的基础知识来构建一个属于自己的持久层框架,将会涉及到的一些知识点:工厂模式
  • Factory 工厂模式
  • 构造者模式(Builder 模式)
  • 代理模式
  • 反射
  • 自定义注解,注解的反射,xml 解析,
  • 数据库元数据,元数据的反射等
image.png

根据代理Dao实现CRUD操作(XML方式实现)

1、查询操作

UserDao中添加接口

 User findById(Integer userId);
<select id="findById" resultType="com.it.pojo.User" parameterType="int">
            select * from user where id = #{uid}
 </select>

注: resultType:返回结果集的类型
parameterType:用于指定传入参数的类型
sql 语句中使用#{} 字符 :
它代表占位符,相当于原来 jdbc 部分所学的?,都是用于执行语句时替换实际的数据。具体的数据是由#{}里面的内容决定的。

{} 中内容的写法:

由于数据类型是基本类型,所以此处可以随意写。
#{} 中内容的写法:
由于数据类型是基本类型,所以此处可以随意写。

2、测试
public class MybatisTest {

    private InputStream in;
    private SqlSessionFactory factory;
    private SqlSession sqlSession;
    private UserDao userDao;

    @Test
    public void test(){
        User user =userDao.findById(41);
        System.out.println(user);
    }
    @Before
    public void init() throws Exception{
        //1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建SqlSessionFactory的构建对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //3.使用创建工厂对象
        factory = builder.build(in);
        //4.创建sqlsession
        sqlSession = factory.openSession();
        //5.使用sqlsession创建dao接口代理的对象
         userDao = sqlSession.getMapper(UserDao.class);
    }
    @After
    public void destroy() throws Exception{
        sqlSession.commit();
        sqlSession.close();
        in.close();
    }
}

2、保存操作

int saveUser(User user);
<insert id="saveUser" parameterType="com.it.pojo.User" >
            insert into user(username,birthday,sex,address)
            values(#{username},#{birthday},#{sex},#{address})
</insert>

注意parameterType 属性:代表参数的类型,因为我们要传入的是一个类的对象,所以类型就写类的全名称。

sql 语句中使用#{}字符:它代表占位符,相当于原来 jdbc 部分所学的?,都是用于执行语句时替换实际的数据。具体的数据是由#{}里面的内容决定的。

#{}中内容的写法:由于我们保存方法的参数是 一个 User 对象,此处要写 User 对象中的属性名称。

#{user.username}它会先去找 user 对象,然后在 user 对象中找到 username 属性,并调用getUsername()方法把值取出来。但是我们在 parameterType 属性上指定了实体类名称,所以可以省略 user.而直接写 username。

它用的是 ognl 表达式。ognl 表达式:
它是 apache 提供的一种表达式语言,全称是:
Object Graphic Navigation Language 对象图导航语言
它是按照一定的语法格式来获取数据的。
语法格式就是使用 #{对象.对象}的方式

    @Test
    public void testSave(){
        User user = new User();
        user.setUsername("nihao");
        user.setAddress("上海");
        user.setSex("男");
        user.setBirthday(new Date());
        System.out.println(user);
        userDao.saveUser(user); //插入
        System.out.println(user);
    }

如果没有提交事务,结果是不会写入到mysql数据库中的

 @After
    public void destroy() throws Exception{
        sqlSession.commit();
        sqlSession.close();
        in.close();
    }
如何获取新增用户 id 的返回值
<insert id="saveUser" parameterType="com.it.pojo.User" >
            <!--  配置保存时获取插入的 id -->
            <selectKey keyColumn="id" keyProperty="id" resultType="int">
                select last_insert_id();
            </selectKey>
            insert into user(username,birthday,sex,address)
            values(#{username},#{birthday},#{sex},#{address})
 </insert>

返回结果会封装到user的pojo对象中,事务的回滚也会消耗id


image.png

3、更新操作

int updateUser(User user);
 <!-- 更新用户 -->
        <update id="updateUser" parameterType="com.it.pojo.User">
            update user set username=#{username},birthday=#{birthday},sex=#{sex},
            address=#{address} where id=#{id}
        </update>
    @Test
    public void testUpdate(){
        User user = userDao.findById(52);
        //更新
        user.setAddress("美国");
        int res = userDao.updateUser(user);
        System.out.println(res);
    }

此时的res返回为1,操作了一条数据

4、删除操作

int deleteUser(Integer userId);
<delete id="deleteUser" parameterType="int">
            delete from user where id = #{uid}
</delete>
   @Test
    public void testDelte(){
        int i = userDao.deleteUser(52);
        System.out.println(i);
        User user = userDao.findById(52);
        System.out.println(user);
    }

5、用户模糊查询

List<User> findByName (String username);
<select id="findByName" parameterType="String" resultType="com.it.pojo.User" >
            select * from user where username like #{username}
 </select>
    @Test
    public void testFindByName(){
        List<User> list = userDao.findByName("%王%");
        for (User user:list){
            System.out.println(user);
        }
    }
image.png

在输入查询参数的时候,使用了%
配置文件中的#{username}也只是一个占位符, SQL 语句显示为“?”。

模糊查询的另外一种配置
<select id="findByName" parameterType="String" resultType="com.it.pojo.User" >
            select * from user where username like '%${value}%'
 </select>

我们在上面将原来的#{}占位符,改成了 ${value}。注意如果用模糊查询的这种写法,那么${value}的写法就是固定的,不能写成其它名字。在他的外面再加上%模糊匹配符合

image.png
可以发现,我们在程序代码中就不需要加入模糊查询的匹配符%了,这两种方式的实现效果是一样的,但执行的语句是不一样的。

{}与${}的区别

#{} 表示一个占位符号
通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换,#{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类型值,#{}括号中可以是 value 或其它名称。

${} 表示拼接 sql 串
通过${}可以将 parameterType 传入的内容拼接在 sql中且不进行 jdbc 类型转换,${}可以接收简单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,${}括号中只能是 value

模糊查询的${value}源码分析
image.png

这就说明了源码中指定了读取的 key 的名字就是”value”,所以我们在绑定参数时就只能叫 value 的名字
了。

5、用户聚合查询

统计用户数量

 int findTotal();
<select id="findTotal" resultType="int">
            select count(*) from user;
</select>
    @Test
    public void testFindTotal(){
        int total = userDao.findTotal();
        System.out.println(total);
    }

mybatis 与 JDBC 比较
1.数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
解决:
在 SqlMapConfig.xml 中配置数据链接池,使用连接池管理数据库链接。
2.Sql 语句写在代码中造成代码不易维护,实际应用 sql 变化的可能较大,sql 变动需要改变 java 代码。
解决:
将 Sql 语句配置在 XXXXmapper.xml 文件中与 java 代码分离。
3.向sql语句传参数麻烦,因为sql语句的where 条件不一定,可能多也可能少,占位符需要和参数对应。
解决:
Mybatis自动将 java 对象映射至 sql 语句,通过 statement 中parameterType 定义输入参数的类型。
4.对结果集解析麻烦,sql 变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成 pojo 对象解析比较方便。
解决:
Mybatis自动将 sql执行结果映射至 java 对象,通过 statement 中的 resultType 定义输出结果的类型。

相关文章

网友评论

    本文标题:02Mybatis 实现CRUD

    本文链接:https://www.haomeiwen.com/subject/rmafwhtx.html