mybatis的学习笔记

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis的学习笔记相关的知识,希望对你有一定的参考价值。

     前几天学习了mybatis,今天来复习一下它的内容。

     mybatis是一个基于Java的持久层框架,那就涉及到数据库的操作。首先来提出第一个问题:java有jdbc连接数据库,我们为什么还要使用框架呢?要回答这个问题,首先来看一下jdbc是怎样编程的。

     

 1 private static String sql = "SELECT * FROM USER WHERE username =  ?";
 2     
 3     public static void main(String[] args) throws SQLException {
 4         
 5         //数据库连接
 6         Connection connection = null;
 7         //预编译statement
 8         //好处:防止 sql注入,提高数据的性能
 9         PreparedStatement preparedStatement = null;
10         //结果集
11         ResultSet resultSet = null;
12         
13         try {
14             
15             //加载数据库驱动
16             Class.forName("com.mysql.jdbc.Driver");
17             
18             //连接数据库
19             connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis", "root", "mysql");
20             
21             //构造preparedStatement
22             preparedStatement = connection.prepareStatement(sql);
23             //向preparedStatement中占位符的位置设置参数
24             preparedStatement.setString(1, "张三");
25             
26             //发起数据库查询请求,得到结果集
27             resultSet = preparedStatement.executeQuery();
28             //遍历查询结果
29             
30             while(resultSet.next()){
31                 int id = resultSet.getInt("id");
32                 String username = resultSet.getString("username");
33                 Date birthday = resultSet.getDate("birthday");
34                 System.out.println(id+"   "+username+"    "+birthday);
35             }
36             
37             
38         } catch (Exception e) {
39             e.printStackTrace();
40         }finally{
41             //释放资源
42             if(resultSet!=null){
43                 resultSet.close();
44             }
45             if(preparedStatement!=null){
46                 preparedStatement.close();
47             }
48             if(connection!=null){
49                 connection.close();
50             }
51         }
52         
53         
54     }
55 
56 }

从上面代码总结一下jdbc编程中的一些问题:

 

1、 sql语句硬编码到java代码中,如果修改sql语句,需要修改java代码,重新编译。系统可维护性不高。

设想如何解决?

能否将sql单独 配置在配置文件中。

 

2、 数据库连接频繁开启和释放,对数据库的资源是一种浪费。

设想如何解决?

使用数据库连接池管理数据库连接。

 

3、 preparedStatement中占位符的位置设置参数时,存在硬编码(占位符的位置,设置的变量值)

设想如何解决?

能否也通过配置的方式,配置设置的参数,自动进行设置参数。

 

4、 解析结果集时存在硬编码(表的字段名、字段的类型)

设想如何解决?

能否将查询结果集映射成java对象。

 

先来看看Mybatis的流程图:

 

技术分享

以一个具体的案例来说明,先来看看表:

技术分享

这张表已经被我使用过多次,插入一些数据了。

接下来,第一件事,导包。(会maven的童鞋自己去百度下pom.xml的配置,这个小案例我这里就不用maven了)

技术分享

项目的整体目录是这个样子的:

技术分享

先来讲config这个目录下:

技术分享

全局配置文件:SqlMapConfig.xml文件内容:

数据库运行环境(和spring整合则去掉这部分)

Mapper映射文件。

实现延迟加载,打开二级缓存。

定义别名。

代码如下:

 

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE configuration
 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 4 "http://mybatis.org/dtd/mybatis-3-config.dtd">
 5 <configuration>
 6     <!-- 加载数据库连接参数配置文件 -->
 7     <properties resource="db.properties" />
 8 
 9     <!-- 全局配置参数 -->
10     
11         <settings>
12             <!-- 实现延迟加载 -->
13             <setting name="lazyLoadingEnabled" value="true" />
14             <setting name="aggressiveLazyLoading" value="false" />
15             
16             <!-- 打开二级缓存开关       -->
17             <setting name="cacheEnabled" value="true"/>
18         </settings>
19         
20      
21 
22     <!-- 定义别名 -->
23     <typeAliases>
24         <!-- 单个别名定义 type:pojo的路径 alias:别名的名称 -->
25         <!-- <typeAlias type="com.mybatis.po.User" alias="user"/> -->
26         <!-- 批量别名定义 name:指定包名,将包下边的所有pojo定义别名 ,别名为类名(首字母大写或小写都行) -->
27         <package name="com.mybatis.po" />
28     </typeAliases>
29 
30     <!-- 和spring整合后 environments配置将废除 -->
31     <environments default="development">
32         <environment id="development">
33             <transactionManager type="JDBC" />
34             <dataSource type="POOLED">
35                 <property name="driver" value="${jdbc.driver}" />
36                 <property name="url" value="${jdbc.url}" />
37                 <property name="username" value="${jdbc.username}" />
38                 <property name="password" value="${jdbc.password}" />
39             </dataSource>
40         </environment>
41     </environments>
42 
43     <!-- 配置mapper映射文件 -->
44     <mappers>
45         <!-- resource方式 在UserMapper.xml,定义namespace为mapper接口的地址,映射文件通过namespace找到对应的mapper接口文件 -->
46         <!-- <mapper resource="sqlmap/UserMapper.xml" /> -->
47         <!-- class方式 class:指定 mapper接口的地址 遵循规则:将mapper.xml和mapper.java文件放在一个目录 
48             且文件名相同 -->
49         <!-- <mapper class="com.mybatis.mapper.UserMapper"/> -->
50 
51 
52         <!--批量mapper扫描 遵循规则:将mapper.xml和mapper.java文件放在一个目录 且文件名相同 -->
53         <package name="com.mybatis.mapper" />
54 
55 
56     </mappers>
57 </configuration>

 

 

 

db.properties

 

1 jdbc.driver=com.mysql.jdbc.Driver
2 jdbc.url=jdbc:mysql://localhost:3306/test
3 jdbc.username=root
4 jdbc.password=202011

 

log4j.properties:使用debug。

1 # Global logging configuration
2 log4j.rootLogger=DEBUG, stdout
3 # Console output...
4 log4j.appender.stdout=org.apache.log4j.ConsoleAppender
5 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
6 log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

 

 

po类:user.java  要存入二级缓存,所以序列化了。

 

 1 package com.mybatis.po;
 2 
 3 import java.io.Serializable;
 4 
 5 
14 public class User implements Serializable{
15 
16     /**
17      * 
18      */
19     private static final long serialVersionUID = 1L;
20     
21     private int id;
22     private String username;// 用户姓名
23 
24     private String age;
25 
26     private String sex;// 性别
27     private String address;// 地址
28     private String detail;// 详细信息
29     public User() {
30     
31         
32     }
33     public User(String username) {
34         super();
35         this.username = username;
36     }
37     
38     public String getAge() {
39         return age;
40     }
41     public void setAge(String age) {
42         this.age = age;
43     }
44     public int getId() {
45         return id;
46     }
47     public void setId(int id) {
48         this.id = id;
49     }
50     public String getUsername() {
51         return username;
52     }
53     public void setUsername(String username) {
54         this.username = username;
55     }
56     public String getSex() {
57         return sex;
58     }
59     public void setSex(String sex) {
60         this.sex = sex;
61     }
62     
63     public String getAddress() {
64         return address;
65     }
66     public void setAddress(String address) {
67         this.address = address;
68     }
69     public String getDetail() {
70         return detail;
71     }
72     public void setDetail(String detail) {
73         this.detail = detail;
74     }
75     
76     @Override
77     public String toString() {
78         return "User [id=" + id + ", username=" + username + ", age=" + age
79                 + ", sex=" + sex + ", address=" + address + ", detail="
80                 + detail + "]";
81     }
82     
83     
84     
85 
86 }

 

 

 

配置mybatis的mapper映射文件:

userMapper.xml:

 

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE mapper
 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 5 <!-- namespace命名空间特殊作用: 如果使用mapper动态代理方法,这里就需要配置mapper接口地址-->
 6 
 7 <mapper namespace="com.mybatis.mapper.UserMapper">
 8     <!-- 根据用户id查询一条记录(返回单条记录) -->
 9     <!-- 
10     select标签表示sql查询,内容会封装到Mapped Statement中。
11     可以将这个select标签称为一个Statement
12     id:Statement的id,用于标识select中定义的 sql,id是在同一个命名空间中不允许重复
13     #{}:表示一个占位符,避免sql注入
14     parameterType:表示输入参数的类型
15     resultType:表示输出 结果集单条记录映射的java对象类型,select查询的字段名和resultType中属性名一致,才能映射成功。
16     #{value}:value表示parameter输入参数的变量,如果输入参数是简单类型,使用#{}占位符,变量名可以使用value或其它的名称 
17     
18      -->
19     <select id="findUserByName" parameterType="String" resultType="User" useCache="false">
20         
21         SELECT * FROM USER WHERE username = #{username}
22     
23     </select>
24     
25     
26     <select id="findUserById" parameterType="int" resultType="User">
27         
28         SELECT * FROM USER WHERE id= #{id}
29     
30     </select>
31     
32     
33     <!-- 查询用户列表(返回list集合) -->
34     <!-- 
35     不管结果集查询一条还是多条,resultType指定结果集单条记录映射的java对象类型
36     ${}:表示sql拼接,相当于sql字符串拼接,无法避免sql注入
37     ${value}:value表示parameter输入参数的变量,如果输入参数是简单类型,使用${}拼接符,变量名必须使用value
38     ${value}直接 将value获取到拼接在sql中,value值不加任何修饰
39      -->
40     <select id="findUserList" parameterType="java.lang.String" resultType="User" >
41       SELECT * FROM USER WHERE username like ‘%${value}%‘
42     </select>
43     
44     
45     <!-- 添加用户
46     parameterType:如果parameterType指定 是pojo,在#{}中指定 pojo的属性名获取该pojo的属性值 
47      -->
48     <insert id="insertUser" parameterType="User"   useGeneratedKeys="true" keyProperty="id">
49     
50     <!-- 
51     useGeneratedKeys设置true表明要mybatis获取由数据库自动生成的主键
52     keyProperty:将主键设置到pojo中哪个属性中
53     order:selectKey中sql执行的时机
54     resultType:selectKey中sql执行的结果类型
55     LAST_INSERT_ID:是insert后获取自增主键值 
56      -->
57      <!-- 
58     <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
59          select LAST_INSERT_ID()
60     </selectKey>
61         -->
62     insert into user(username,sex,address,detail)
63      values(#{username},#{sex},#{address},#{detail})
64     </insert>
65 
66     <!-- 根据主键删除用户 -->
67     
68     <delete id="deleteUser" parameterType="java.lang.String">
69        delete from user where username =#{username}
70     </delete>
71     
72     <!-- 根据主键用户更新
73     更新传入输入参数见容:id和更新的信息
74      -->
75     <update id="updateUser" parameterType="User" >
76        update user set username=#{username},sex=#{sex},address=#{address},detail=#{detail}  where id=#{id}
77     </update>
78     
79     
80 <cache/>
81 </mapper>

 

userMapper.java:

 1 package com.mybatis.mapper;
 2 
 3 import java.util.List;
 4 
 5 import com.mybatis.po.User;
 6 
 7 
 8 
17 public interface UserMapper {
18     
19     //根据用户id查询用户信息
20     public User findUserById(int id) throws Exception;
21     
22     //根据用户名字查询信息
23     public User findUserByName(String username) throws Exception;
24     
25     //查询用户列表
26     public List<User> findUserList(String username)throws Exception;
27     
28     public void deleteUser(String username)throws Exception;
29     
30     public int insertUser(User user)throws Exception;
31     
32     public void updateUser(User user)throws Exception;
33 
34 }

 

 

Test.java:

 

  1 package com.mybatis.mapper;
  2 
  3 import java.io.InputStream;
  4 import java.util.List;
  5 
  6 import org.apache.ibatis.io.Resources;
  7 import org.apache.ibatis.session.SqlSession;
  8 import org.apache.ibatis.session.SqlSessionFactory;
  9 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
 10 import org.junit.Before;
 11 import org.junit.Test;
 12 
 13 import com.mybatis.po.User;
 14 
 15 public class UserMapperTest {
 16 
 17     // 会话工厂
 18     private SqlSessionFactory sqlSessionFactory;
 19 
 20     @Before
 21     public void setUp() throws Exception {
 22         // 加载配置文件
 23         String resource = "SqlMapConfig.xml";
 24         InputStream inputStream = Resources.getResourceAsStream(resource);
 25 
 26         // 根据mytais的配置创建SqlSessionFactory
 27 
 28         sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
 29 
 30         //sqlSessionFactory.getConfiguration().addMapper(UserMapper.class);
 31     }
 32 
 33     @Test
 34     public void testFindUserByName() throws Exception {
 35         SqlSession sqlSession = sqlSessionFactory.openSession();
 36         //通过sqlSession创建代理对象(接口的实现类对象)
 37         UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 38         User user= userMapper.findUserByName("张小三");
 39         System.out.println(user);
 40     }
 41 
 42     @Test
 43     public void testFindUserList() throws Exception {
 44         SqlSession sqlSession = sqlSessionFactory.openSession();
 45         //通过sqlSession创建代理对象(接口的实现类对象)
 46         UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 47         List<User> list = userMapper.findUserList("d");
 48         for(User x:list){
 49             System.out.println(x.getUsername());
 50         }
 51         
 52         
 53     }
 54     
 55     /*
 56      由于我的这个user表被其他表的外键连接,所以这里暂不进行删除操作。
 57     @Test
 58     public void deleteUser() throws Exception {
 59         SqlSession sqlSession = sqlSessionFactory.openSession();
 60         //通过sqlSession创建代理对象(接口的实现类对象)
 61         UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 62         userMapper.deleteUser("duyu");
 63         sqlSession.commit();
 64         sqlSession.close();
 65         
 66         
 67     }
 68     */
 69 
 70     
 71     @Test
 72     public void insertUser() throws Exception {
 73         SqlSession sqlSession = sqlSessionFactory.openSession();
 74         //通过sqlSession创建代理对象(接口的实现类对象)
 75         UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 76         User user=new User("2017-3-12");
 77         user.setAddress("四川");
 78         int z=userMapper.insertUser(user);
 79         sqlSession.commit();
 80         sqlSession.close();
 81         System.out.println(z);
 82         
 83     }
 84     
 85     @Test
 86     public void updateUser() throws Exception {
 87         SqlSession sqlSession = sqlSessionFactory.openSession();
 88         //通过sqlSession创建代理对象(接口的实现类对象)
 89         UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
 90         User user=userMapper.findUserByName("duu");
 91         user.setAddress("北京");
 92         user.setUsername("Eminem");
 93         userMapper.updateUser(user);
 94         sqlSession.commit();
 95         sqlSession.close();
 96         
 97         
 98     }
 99 
100 }

 

 

 

执行完操作后表如下:

技术分享

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定义输出结果的类型。

 

以上是关于mybatis的学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

MyBatis-05-笔记

学习笔记:python3,代码片段(2017)

mybatis学习(39):动态sql片段

mybatis学习笔记使用generator生成mybatis基础配置代码和目录结构

Mybatis学习笔记-增删改的操作 -对SqlSession的优化封装-优化代码

MyBatis学习笔记