ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 2.1 一个简单的权限控制需求 ### 2.1.2 创建实体类 特殊的类型“byte[]"一般对应数据库中的 BLOB、LONGVARBINARY 以及一些和二进制流有关的字段类型。 **由于Java中的基本类型会有默认值,例如当某个类中存在private int age;字段时,创建这个类时,age会有默认值0。当使用age属性时,它总会有值。因此在某些情况下,便无法实现使age为null。并且在动态SQL的部分,如果使用age!=null进行判断,结果总会为true,因而会导致很多隐藏的问题。** ## 2.2 使用XML方式 ```     <mappers>         <mapper resource="tk.mybatis.simple.mapper"/>     </mappers> ``` 1. 这种配置方式会先查找tk.mybatis.simple.mapper包下所有的接口,循环对接口进行如下操作: 2. 判断接口对应的命名空间是否已经存在,如果不存在就抛出异常,存在进行下来的操作。 3. 加载接口对应的 XML 映射文件,将接口全限定名转换为路径,例如,将接口tk.mybatis.simple.mapper.UserMapper转换为tk/mybatis/simple/mapper/UserMapper.xml,以.xml为后缀搜索XML资源,如果找到就解析XML。 4. 处理接口中的注解方法。 ## 2.3 select用法 *因为接口方法是可以重载的,所以接口中可以出现多个同名但参数不同的方法,但是XML中id的值不能重复,因而接口中的所有同名方法会对应着XML中的同一个id的方法。最常见的用法就是,同名方法中其中的一个方法增加一个 RowBound 类型的参数用于实现分页查询。* XML中的resultType(或resultMap中的type)决定的接口中写的返回值类型,两者要一致。 MyBatis 还提供了一个全局属性mapUnderscoreToCamelCase,通过配置这个属性为true可以自动将以下画线方式命名的数据库列映射到Java对象的驼峰式命名属性中。想要使用该功能,在MyBatis-config.xml中增加如下配置。 <setting name="mapUnderscoreToCamelCase" value="true"/> 注意!:xml中sql语句返回类型最好使用restultMap不要用resultType,因为resultType映射时属性名和列名必须一致。 XML中的select标签的id属性值和定义的接口方法名是一样的。MyBatis就是通过这种方式将接口方法和XML中定义的SQL语句关联到一起的。 **resultMap标签** · jdbcType:列对应的数据库类型。插入、更新、删除操作可能为空的列进行处理。这是JDBC jdbcType的需要,不是MyBatis的需要。  type: 必填, 用于配置查询列所映射到的Java对象类型 ##### 测试类 ``` /**  * 生成sqlSessionFactory实例  * 基础测试类  */ public class BaseMapperTest {      private static SqlSessionFactory sqlSessionFactory;            @BeforeClass      public static void init(){           try {             Reader reader = Resources.getResourceAsReader("mybatis-config.xml");             sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);             reader.close();         } catch (IOException ignore) {           ignore.printStackTrace();         }      }      public SqlSession getSqlSession(){           return sqlSessionFactory.openSession();      } } public class UserMapperTest extends BaseMapperTest {            @Test      public void testSelectById(){           //获取 sqlSession           SqlSession sqlSession = getSqlSession();           try {               //获取 UserMapper 接口               UserMapper userMapper = sqlSession.getMapper(UserMapper.class);               //调用UserMapper 接口中的 selectById 方法,查询 id = 1 的用户               SysUser user = userMapper.selectById(1l);               //user 不为空               Assert.assertNotNull(user);               //userName = <u>admin</u>               Assert.assertEquals("admin", user.getUserName());           } finally {               //不要忘记关闭 sqlSession               sqlSession.close();           }      } } ``` ## 2.4 insert用法 注意 : 插入表时,为确定记录的唯一性。 1.用数据库自己生成的值 2.从序列当中取值作为主键值 (可以【mysql】和不可以【oracle】自己生成主键值的数据库都能用) ### 2.4.1 简单的insert方法 ```      <insert id="insert">           insert into sys_user(               user_name, user_password, user_email,               user_info, head_img, create_time)           values(               #{userName}, #{userPassword}, #{userEmail},               #{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP})      </insert> ``` 先看<insert>元素,这个标签包含如下属性。 · id:命名空间中的唯一标识符,可用来代表这条语句。 · parameterType:即将传入的语句参数的完全限定类名或别名。这个属性是可选的,因为MyBatis可以推断出传入语句的具体参数,因此不建议配置该属性。 · flushCache:默认值为true,任何时候只要语句被调用,都会清空一级缓存和二级缓存。· timeout:设置在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。 · statementType:对于STATEMENT、PREPARED、CALLABLE,MyBatis会分别使用对应的 Statement、PreparedStatement、CallableStatement,默认值为PREPARED。· useGeneratedKeys:默认值为 false。如果设置为 true,MyBatis 会使用 JDBC的getGeneratedKeys方法来取出由数据库内部生成的主键。 · keyProperty:MyBatis通过getGeneratedKeys获取主键值后将要赋值的属性名。如果希望得到多个数据库自动生成的列,属性值也可以是以逗号分隔的属性名称列表。 · keyColumn:仅对INSERT和UPDATE有用。通过生成的键值设置表中的列名,这个设置仅在某些数据库(如 PostgreSQL)中是必须的,当主键列不是表中的第一列时需要设置。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 · databaseId:如果配置了databaseIdProvider(4.6节有详细配置方法),MyBatis会加载所有的不带databaseId的或匹配当前databaseId的语句。如果同时存在带databaseId和不带databaseId的语句,后者会被忽略。此处<insert>中的 SQL 就是一个简单的 INSERT 语句,将所有的列都列举出来,在values中通过#{property}方式从参数中取出属性的值。 为了防止类型错误,对于一些特殊的数据类型,建议指定具体的 jdbcType 值。例如headImg指定BLOB类型,createTime指定TIMESTAMP类型。特别说明!BLOB对应的类型是ByteArrayInputStream,就是二进制数据流。由于数据库区分date、time、datetime类型,但是Java中一般都使用java.util.Date类型。因此为了保证数据类型的正确,需要手动指定日期类型,date、time、datetime对应的JDBC类型分别为DATE、TIME、TIMESTAMP。 数据库的datetime类型可以存储DATE(time部分默认为00:00:00)和TIMESTAMP(时间戳)这两种类型的时间,不能存储TIME类型的时间。 ###  2.4.2 使用JDBC方式返回主键自增的值  用数据库内部自动生成的主键值给指定的列 (id) 赋值。 下面的insert语句当中不用再写id列列名和值。 ``` <insert id="insert2" useGeneratedKeys="true" keyProperty="id"> </insert> ``` keyColumn :  数据库表中主键列的名字。 当需要设置多个属性时, 使用逗号隔开 这种情况下通常还需要设置 keyColumn 属性, 按顺序指定数据库的列。 keyProperty: 主键列对应的java类中属性名。 useGeneratedKeys = true使用自动生成的主键值给指定列赋值。 ###  2.4.3 使用selectKey返回主键的值  有些数据库(如 Oracle) 不提供主键自增的功能, 而是使用序列得到一个值。 使用<selectKey>标签来获取主键的值, 这种方式不仅适用于不提供主键自增功能的数据库, 也适用于提供主键自增功能的数据库。 ###### Oracle: ``` <!-- Oracle 的例子,查询多个列的时候需要 keyColumn --> <insert id="insertOracle"> <selectKey keyColumn="id" resultType="long" keyProperty="id" order="BEFORE"> SELECT SEQ_USER.nextval from dual </selectKey> insert into sys_user( id, user_name, user_password, user_email, user_info, head_img, create_time) values( #{id}, #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP}) </insert> ``` ###### insert语句中要写主键列 (id) insert into sys_user(id,...) **原因**  在Oracle数据库中,需要先从序列获取id值, 然后将值赋给入参,再插入到数据库中。 order = "BEFORE" * * * ###### MySQL ``` <insert id="insert3"> insert into sys_user( user_name, user_password, user_email, user_info, head_img, create_time) values( #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP}) <selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER"> SELECT LAST_INSERT_ID() </selectKey> </insert> ``` ###### insert语句中不需要写主键列 (id) insert into sys_user(username,...) **原因** 在MySQL数据库中,先执行insert语句,再将获得的主键值插入到表中,order="AFTER"。 keyProperty="id" 应该可以不写。 ##  2.5 update用法 根据id更新表中一条数据 ## 2.6 delete用法 根据id删除表中一条数据 //判断值是否相等  Assert.assertEquals(1, result); //判断不为空 Assert.assertNull(user.getId()); ##  2.7 Mapper接口方法有多个参数的用法 ###### mapper方法接口有多个参数时,加参数前加@param注解: ![40249da3d7f015fb1529c9b9a42dbca8.png](en-resource://database/546:1) ![acfe0fde89fc9246ae80daa29d56a6d8.png](en-resource://database/549:1) ###### 一个mapper方法接口有多个参数时的错误用法及报错信息: ![65f57fa93c6a6b541eafc012b0cf7d24.png](en-resource://database/547:1) ![3e9c3ea97e7c09d10261a04fe31c726a.png](en-resource://database/545:1) **报错原因:** 这个错误表示, XML可用的参数只有0、 1、 param1、 param2, 没userId。 0和1 , param1和param2都是MyBatis根据参数位置自定义的名这时如果将XML中的#{userId}改为#{0}或#{param1}, 将#{enabled}改为#{1}或#{param2}, 这个方法就可以被正常调用了,但不要这么做。 但当只有一个参数(基本类型或拥有TypeHandler配置的类型) 的时候, MyBatis不关心这个参数叫什么名字就会直接把这个唯一的参数值拿来使用。 **接口中参数是两个或两个以上的JavaBean时,代码如图:** ![84559d2d237afc31953978b53f768811.png](en-resource://database/548:1)  在XML中就不能直接使用#{userId}和#{enabled}了, 而是要通过点取值方式使用#{user.id}和#{role.enabled}从两个JavaBean中取出指定属性的值。 ##  2.8 Mapper接口动态代理实现原理 *为什么Mapper接口没有实现类却能被正常调用呢?* *动态代理不熟悉 需要读关于代理设计模式的代码*