环境搭建

第一步,创建maven工程并导入坐标

  1. <dependencies>
  2. <!-- 导入坐标 -->
  3. <dependency>
  4. <groupId>com.totoro</groupId>
  5. <artifactId>mybatis_user</artifactId>
  6. <version>3.5.5</version>
  7. </dependency>
  8. <dependency>
  9. <groupId>mysql</groupId>
  10. <artifactId>mysql-connector-java</artifactId>
  11. <version>8.0.21</version>
  12. </dependency>
  13. <dependency>
  14. <groupId>log4j</groupId>
  15. <artifactId>log4j</artifactId>
  16. <version>1.2.12</version>
  17. </dependency>
  18. <dependency>
  19. <groupId>junit</groupId>
  20. <artifactId>junit</artifactId>
  21. <version>4.12</version>
  22. </dependency>
  23. <dependency>
  24. <groupId>org.mybatis</groupId>
  25. <artifactId>mybatis</artifactId>
  26. <version>3.5.5</version>
  27. <scope>test</scope>
  28. </dependency>
  29. <dependency>
  30. <groupId>org.mybatis</groupId>
  31. <artifactId>mybatis</artifactId>
  32. <version>3.5.5</version>
  33. <scope>compile</scope>
  34. </dependency>
  35. </dependencies>

第二步,创建实体类和dao的接口

  1. public class User implements Serializable {
  2. private Integer id;
  3. private String username;
  4. private Date birthday;
  5. private String gender;
  6. private String address;
  7. // get & set or toString functions
  8. }
  1. /*
  2. * 用户持久层接口
  3. * 在 xml 里面写sql语句
  4. * */
  5. public interface IUserDao {
  6. /*
  7. * 查询所有用户
  8. * @return
  9. * */
  10. List<User> findAll();
  11. /*
  12. * 保存用户
  13. * @param user
  14. * */
  15. void saveUser(User user);
  16. /*
  17. * 更新用户信息
  18. * @param user
  19. * */
  20. void updateUser(User user);
  21. /*
  22. * 根据id删除用户
  23. * @param id
  24. * */
  25. void deleteUser(int id);
  26. /*
  27. * 根据id查找用户
  28. * @param id
  29. * */
  30. User findById(Integer id);
  31. /*
  32. * 模糊查询用户信息
  33. * @param username
  34. * */
  35. List<User> findByName(String username);
  36. /*
  37. * 查询所有用户数
  38. * */
  39. int findTotal();
  40. /*
  41. * 根据传入的参数查询
  42. * @param user 查询的条件:用户名或性别或地址或全部
  43. * @return
  44. * */
  45. List<User> findUserByCondition(User user);
  46. /*
  47. * 用户到角色的多对多关系
  48. * @return
  49. * */
  50. List<User> findUserToRole();
  51. }

第三步,创建mybatis的主配置文件 SqlMapConfig.xml

  1. <configuration>
  2. <!-- 配置别名,只能配置domain中类的别名,当指定了别名就不再区分大小写 -->
  3. <typeAliases>
  4. <!-- <typeAlias type="com.totoro.domain.User" alias="user"></typeAlias>-->
  5. <!-- 用于指定要配置的包,当指定之后,该包内的实体类都会注册别名,并且类名就是别名,不再区分大小写-->
  6. <package name="com.totoro.domain"/>
  7. </typeAliases>
  8. <!-- 配置环境 -->
  9. <environments default="mysql">
  10. <environment id="mysql">
  11. <!-- 配置事务的类型 -->
  12. <transactionManager type="JDBC"></transactionManager>
  13. <!-- 配置数据源(连接池) -->
  14. <dataSource type="POOLED">
  15. <property name="driver" value="com.mysql.cj.jdbc.Driver"></property>
  16. <property name="url" value="jdbc:mysql://localhost:3306/notes?serverTimezone=UTC"></property>
  17. <property name="username" value="root"></property>
  18. <property name="password" value="llqqssyymm1506059428"></property>
  19. </dataSource>
  20. </environment>
  21. </environments>
  22. <!-- 指定映射配置文件的位置 -->
  23. <mappers>
  24. <!-- <mapper resource="com/totoro/dao/IUserDao.xml"/>-->
  25. <!-- 用于指定dao接口所在的包(相当于别名),当指定之后就不再需要写mapper resource class了-->
  26. <package name="com.totoro.dao"/>
  27. </mappers>
  28. <!--注解方式:此处使用class属性指定被注解的dao全限定类名
  29. <mappers>
  30. <mapper class="com.totoro.dao.IUserDao"/>
  31. </mappers> -->
  32. </configuration>

第四步,创建映射配置文件 IUserDao.xml

  1. <mapper namespace="com.totoro.dao.IUserDao">
  2. <!-- 配置 查询结果的列名和实体类的属性名的对应关系 -->
  3. <resultMap id="userMap" type="com.totoro.domain.User">
  4. <!-- 主键 -->
  5. <id property="id" column="id"></id>
  6. <!-- 非主键 -->
  7. <result property="username" column="username"></result>
  8. <result property="birthday" column="birthday"></result>
  9. <result property="gender" column="gender"></result>
  10. <result property="address" column="address"></result>
  11. <collection property="roles" ofType="role">
  12. <id property="roleId" column="id"></id>
  13. <result property="roleName" column="role_name"></result>
  14. <result property="roleDesc" column="role_desc"></result>
  15. </collection>
  16. </resultMap>
  17. <!-- 配置查询所有用户, id为方法名称 -->
  18. <select id="findAll" resultMap="userMap">
  19. select * from user
  20. </select>
  21. <!-- 插入信息 -->
  22. <insert id="saveUser" parameterType="User">
  23. <!-- 配置插入操作后,获取插入数据的id -->
  24. <selectKey keyProperty="id" resultType="int" order="AFTER">
  25. select last_insert_id();
  26. </selectKey>
  27. insert into user(username, address,gender,birthday)values (#{username},#{address},#{gender},#{birthday})
  28. </insert>
  29. <!-- 更新用户信息 -->
  30. <update id="updateUser" parameterType="User">
  31. update user set username=#{username},address=#{address},birthday=#{birthday},gender=#{gender} where id=#{id}
  32. </update>
  33. <!-- 删除用户 -->
  34. <delete id="deleteUser" parameterType="int">
  35. delete from user where id=#{id}
  36. </delete>
  37. <!-- 查询用户 -->
  38. <select id="findById" parameterType="integer" resultMap="userMap">
  39. select * from user where id= #{id}
  40. </select>
  41. <!-- 根据名称模糊查询 -->
  42. <select id="findByName" parameterType="string" resultMap="userMap">
  43. select * from user where username like #{username}
  44. </select>
  45. <select id="findTotal" resultType="integer">
  46. select count(id) from user
  47. </select>
  48. <!-- 根据条件查询 -->
  49. <select id="findUserByCondition" resultMap="userMap" parameterType="user">
  50. select * from user
  51. <where>
  52. <if test="username != null">
  53. and username = #{username}
  54. </if>
  55. <if test="gender != null">
  56. and gender = #{gender}
  57. </if>
  58. </where>
  59. </select>
  60. <select id="findUserToRole" resultMap="userMap">
  61. select u.*,r.id,r.role_name,r.role_desc from user u
  62. LEFT OUTER JOIN user_role ur on u.id = ur.uid
  63. LEFT OUTER JOIN role r on r.id=ur.rid
  64. </select>
  65. </mapper>

环境搭建的注意事项:

  1. mybatis中,它把持久层的操作接口名称和映射文件也叫做Mapper,即IUserDaoIUserMapper是一样的
  2. 在idea中,创建目录derectory与创建包package是不一样的,com.totoro.my在创建包时会自动分成3级
  3. mybatis的映射配置文件位置必须和dap接口的包结构一致
  4. 映射配置文件的mapper标签namespace属性必须是dao接口的全限定类名
  5. 映射配置文件的操作配置(如select),其id属性的取值必须是dao接口的方法名

第五步,测试类

  1. 读取配置文件
  2. 创建SqlSessionFactory工厂
  3. 使用工厂生产SqlSession对象
  4. 使用SqlSession创建Dao接口的代理对象
  5. 使用代理对象执行方法
  6. 释放资源
  7. 在测试类 test 里面, @Before@Test 之前执行, @After@Test 之后执行

    1. public class AccountTest {
    2. private InputStream in;
    3. private SqlSession sqlSession;
    4. private IAccountDao iAccountDao;
    5. @Before // 在测试方法执行之前执行
    6. public void init() throws Exception{
    7. // 1. 读取配置文件
    8. in= Resources.getResourceAsStream("SqlMapConfig.xml");
    9. // 2. 创建SqlSessionFactory工厂
    10. SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
    11. SqlSessionFactory factory = builder.build(in);
    12. // 3. 使用工厂生产SqlSession对象
    13. sqlSession = factory.openSession();
    14. // 4. 使用SqlSession创建Dao接口的代理对象
    15. iAccountDao = sqlSession.getMapper(IAccountDao.class);
    16. }
    17. @After // 在测试方法执行之后执行
    18. public void destroy() throws Exception{
    19. // 提交事务
    20. sqlSession.commit();
    21. // 6. 释放资源
    22. sqlSession.close();
    23. in.close();
    24. }
    25. // 查询所有
    26. @Test
    27. public void testFindAll() throws Exception{
    28. List<Account> users = iAccountDao.findAll();
    29. for(Account account:users){
    30. System.out.println(account);
    31. }
    32. }
    33. }
  • 注意事项:需要在映射配置中告知mybatis要封装到那个实体类中;配置方式为制定实体类的全限定类名
  • mybatis基于注解的入门:
    IUserDao.xml移除,在dao接口的方法上使用@Select注解,并且指定SQL语句,同时需要在SqlMapConfig.xml中的mapper配置时,使用class属性指定dao接口的全限定类名。

配置properties

  • 可以在标签内部配置连接数据库的信息,也可以通过属性引用外部配置文件信息
  • resource属性,常用的,用于指定配置文件的位置,按照类路径的写法来写,并且必须存在于类路径下。
  • url属性,按照url的写法来写地址
    URL:uniform resource locator 统一资源定位符,可以唯一标志一个资源的位置,写法:协议+主机名+端口号+URI。URI:uniform resource identifier 统一资源标志符,在应用中唯一定位一个资源
  • 如,新建一个名为 c3p0.properties 的文件

    1. ###### database configuration information ######
    2. c3p0.jdbcUrl=jdbc:mysql://LOCALHOST:3306/status?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
    3. c3p0.driverClass=com.mysql.cj.jdbc.Driver
    4. c3p0.user=root
    5. c3p0.password=llqqssyymm1506059428
    6. ###### C3P0 configuration information ######
    7. c3p0.maxPoolSize=100
    8. c3p0.minPoolSize=1
    9. c3p0.initialPoolSize=5
    10. c3p0.maxIdleTime=1800
  • 在mybaits的配置文件中(或者在mybatis与spring整合的配置文件中)引用:

    1. <!-- 读取c3p0.properties中的数据库配置信息 -->
    2. <context:property-placeholder location="classpath:properties/c3p0.properties"/>
    3. <!-- 配置数据源 -->
    4. <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    5. <!-- 数据库驱动 -->
    6. <property name="driverClass" value="${c3p0.driverClass}"/>
    7. <!-- 连接数据库的url -->
    8. <property name="jdbcUrl" value="${c3p0.jdbcUrl}"/>
    9. <!-- 连接数据库的用户名 -->
    10. <property name="user" value="${c3p0.user}"/>
    11. <!-- 连接数据库的密码 -->
    12. <property name="password" value="${c3p0.password}"/>
    13. <!-- 初始化连接数 -->
    14. <property name="initialPoolSize" value="${c3p0.initialPoolSize}"/>
    15. <!-- 最大连接数 -->
    16. <property name="maxPoolSize" value="${c3p0.maxPoolSize}"/>
    17. <!-- 最小连接数 -->
    18. <property name="minPoolSize" value="${c3p0.minPoolSize}"/>
    19. <!-- 连接的生存时间 -->
    20. <property name="maxIdleTime" value="${c3p0.maxIdleTime}"/>
    21. </bean>

    ps一个出现过的问题,在做毕业设计时,我是这样写mybatis的配置的,但是为了与前几个测试项目的数据库分开,我就单独创建了一个数据库,而这个properties文件我却是直接复制过去的,在毕设项目测试时(连接tb_admin查询信息),但是两个数据库都有tb_admin,只不过毕设的数据库的一个字段变了,导致一直出现一个error: Unknown column ‘account’ in ‘where clause’,我忘记了数据库变了,却一直在找这个字段怎么就没有呢,这个数据表删了又建,过了好久才意识到可能是数据库名没改过来

连接池

  1. 可以减少获取连接时的时间
  2. mybatis中
    • 配置位置,主配置文件SqlMapConfig.xml中的dataSource标签,type属性就是表示采用何种连接池方式
    • 有3种方式:
      POOLED 采用传统的javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实现
      UNPOOLED 没有池的思想
      JNDI 采用服务器提供的JNDI技术实现获取DataSource对象,不同服务器获取到的不一样。

mybatis的事务

  1. 什么是事务
    是??
  2. 事务的四大特性ACID
  3. 不考虑隔离性会产生的3个问题
  4. 解决办法:四种隔离级别

多条件查询

  1. <if>标签
  1. <!-- 根据条件查询 -->
  2. <select id="findUserByCondition" resultMap="userMap" parameterType="user">
  3. select * from user where 1=1
  4. <if test="username != null">
  5. and username = #{username}
  6. </if>
  7. <if test="gender != null">
  8. and gender = #{gender}
  9. </if>
  10. </select>
  1. <where>标签
  1. <!-- 根据条件查询 -->
  2. <select id="findUserByCondition" resultMap="userMap" parameterType="user">
  3. select * from user
  4. <where>
  5. <if test="username != null">
  6. and username = #{username}
  7. </if>
  8. <if test="gender != null">
  9. and gender = #{gender}
  10. </if>
  11. </where>
  12. </select>
  1. <each>

多表查询

  • 一对多、一对一、多对一、多对多

    • 一对一,两个表,通过一个外键连接,
    1. 在实体类中添加主表实体的引用 ```java // 从表实体应该包含一个主表实体的对象引用 private User user;

    public User getUser() { return user; }

    1. 1. 定义封装accountuserresultMap,此处的type属性 由于在主配置文件中写了别名,则由原来的`com.totoro.domain.Account`简写为`account`
    2. ```xml
    3. <resultMap id="accountMap" type="account">
    4. <id property="id" column="aid"></id>
    5. <result property="uid" column="uid"></result>
    6. <result property="money" column="money"></result>
    7. <!-- 一对一的关系映射,配置封装user的内容 -->
    8. <association property="user" column="id">
    9. <id property="id" column="id"></id>
    10. <result property="username" column="username"></result>
    11. <result property="birthday" column="birthday"></result>
    12. <result property="gender" column="gender"></result>
    13. <result property="address" column="address"></result>
    14. </association>
    15. </resultMap>
    1. 配置文件,配置查询所有账户与对应的账户信息

      1. <select id="findAllAU" resultMap="accountMap">
      2. select u.*,a.id as aid,a.uid,a.money from account a, user u where u.id=a.uid
      3. </select>
    2. 在接口文件中添加函数List<Account> findAllAU(); 在测试文件中编写函数完成功能

    • 一对多,左表的一个用户可能对应右表的多个账号
      select * from user u LEFT OUTER JOIN account a on u.id = a.uid
    • 多对多,示例:用户与角色。步骤:
      1.建立两张表,用户表,角色表。让用户表和角色表具有多对多的关系,需要使用中间表,中间表中包含各自的主键,在中间表中是外键。
      2.建立两个实体类,….,让用户和角色的实体类能体现出多对多的关系,各自包含对方一个集合引用
      3.建立两个配置文件
      4.实现配置:
      当查询用户时,可以同时得到用户所包含的所有角色信息
      当查询角色时,可以同时得到角色所赋予的用户信息
      5.多对多按照老师写的有一些问题,当一个用户有多个角色时,只能得到一个角色信息;反之也是。

加载与缓存

  1. Mybatis中的延迟加载,按需加载
    • 在四种表关系中:
    • 一对多、多对多:通常采用延迟加载
    • 多对一、一对一:通常采用立即加载
    • 延迟加载有问题
    • 在主配置文件中添加:
  1. <settings>
  2. <setting name="lazyLoadingEnabled" value="true"/> <!-- 开启延迟加载 -->
  3. <setting name="aggressiveLazyLoading" value="false"/>
  4. </settings>
  1. Mybatis中的缓存
    • 适用于缓存:经常查询,不经常改变,数据的正确与否对最终结果影响不大的
    • 不适用于缓存:经常改变的,数据的正确与否对最终结果影响很大(商品的库存、银行的汇率、股市的牌价)
    • 一级缓存:mybatis中SqlSession对象的缓存。当我们执行查询之后,查询结果会同时存入SqlSession为我们提供的一块区域中,该区域的结构是一个Map,当查询同样的数据时,会先去sqlsession中查询是否有,有的话直接拿。
    • 一级缓存是SqlSession范围的缓存,当调用SqlSession的修改、添加、删除、commit()、close()等方法是,就会清空一级缓存
    • 二级缓存:是Mybatis中SqlSessionFactory对象的缓存,由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。二级缓存中存放的是数据而不是对象。步骤:
      一、让mybatis框架支持二级缓存(在主配置文件中配置)
  1. <settings>
  2. <setting name="cacheEnabled" value="true"/>
  3. </settings>

二、让当前的映射文件支持二级缓存(在IUserDao.xml中配置) <cache/>
三、让当前的操作支持二级缓存(在select标签中配置) useCache="true"

注解开发

  • 一共有四个注解:@Select @Insert @Update @Delete
  • 模糊查询有字符串拼接与参数占位符两种
  • 当实体类中的名称与数据库的名称不一致时,需在dao中使用@Results进行映射
  • 二级缓存,在IUserDao.java(接口)里加上@CacheNamespace(blocking=true)

注意

  • 若用xml形式写sql语句,则
    • xml文件需要与dao的文件名一致
    • xml文件的文件头的路径,必须与对应的dao文件的路径一致

image.png image.pngimage.png