今日目标
1.回顾mybaits的自定义再分析和环境搭建+完善注解的mybaits
2.mybatis的curd(基于代理dao的方式)
3.mybatis中的参数深入及结果集的深入
4.mybaitis中基于传统dao的方式(编写dao的实现类) --了解的内容
5.mybatis中的配置(主配置文件:SqlMapConfig.xml)
* propertis标签
* typeAliases标签
* mappers标签
回顾自定义框架
1.核心的点:IUserDao userdao=SqlSession.getMapper(IUserDao.class) 使用动态代理获取一个实体类
2.我们自己实现的自定义框架里面:sqlsession里面有个selectList()-->做了真正连接数据库的操作。
3.回顾自定义框架:
>SqlSessionFactoryBuilder接收SqlMapConfig.xml文件流,构建出SqlSessionFactory对象
>SqlsessionFacotry读取SqlMap---
>...
4.环境搭建回顾:
* 创建项目
* 在pom.xml中导入角标 [mybatis,mysql,junit,log4j]
* 创建com.theima.domain.User实体类,继承Serializable序列化接口
* 配置resources根目录的SqlMapConfig.xml [配置总环境environments,mysql环境environment,事务transactionManger,连接池dataSource,配置映射文件地址 resource]
* 创建com.iheima.dao.IUserdao持久层接口IUSerDao
* 创建Resources下的com.itheima.dao三层目录包路径下的IUserDao.xml配置文件,并编写select标签的查询语句
* 创建test下的java.com.itheima.dao.mybatisTest的testFindAll()方法,对对应位置的IUserDao接口的findAll方法进行测试。
mybaits day_2 start
1.saveUser 保存用户
* before 用于在测试方法执行之前执行
* after 用于在测试方法执行之后执行
* 所以在测试类中,可以将一些初始化的方法和释放资源的方法进行提取,如init和destory方法。
* 在测试完之后需要提交事务,末尾添加或者提取到destory方法:sqlsession.commit();如果在添加删除修改等操作中,如果没有提交事务,则会没有保存到数据库中,因为事务是默认手动提交的。事务提交需要在资源关闭close之前。
* 自动提交事务方法:Session session=factory.openSession(true);
* select查询语句中values中insert into user(username)values{#{username}}中username是参数名一致。如果参数名是大写,那么也就大写。
2.updateUser 更新用户
* 语句:update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where...
* (测试类中)执行保存方法:userDao.updateUser [先在测试类中创建实体类,再执行更新方法。]
3.根据ID删除用户
* 语句:<delect id= "deleteUser" parameterType="java.lang.Integer/INT/int/Integer">
* delect form user where id=#{id} //id是一个占位符可以随便写
* </delect>
* 执行删除操作:userDao.delectUser(48); //删除id为48的用户
* 上面的其他方法是parameterType通过反射到对象的占位符,所以不能随便起名字,必须跟反射的对象属性名字一一对应,而这里的反射是到基本数据类型或者数据类型的包装类中,所以不需要指定名字,这里的id可以为其他名字都可以。
4.测试查询一个方法:
* 测试语句:User user =userDao.findById(30);
5.根据名称模糊查询信息
* 测试语句:List<User> users=userDao.findByName("%王%");
* 在xml配置文件查询中可以使用'%#{value}%' ,但是在实际开发中建议使用name占位符,不用value,value是固定写死,它是拼接字符串,容易引发sql注入,不安全。
6.保存中的细节:
* keyProperty:User中的id;
* keyColumn:数据库中的id;
* resultType:返回值;
* order:在什么时候执行。
* 语句演示:
* <insert id="saveUser" ParameterType="com.itheima.domain.User">
* <selectKey KeyProperty="id" KeyColumn="id" resultType="int">
* select last_insert_id();
* </selectKey>
* insert into user()...
* </insert>
7.OGNL表达式
* Object Graphic Navigation Language
* 对象 图 导航 语言
* 它是通过对象的取值方法来获取数据。在写法上把get的方法忽略了。
* 格式:对象.属性名
8.内省机制:
* domain实体类中必须设置set方法。java的内省机制,它可以将列名和类进行封装,再通过反射与实体对象对应。
9.映射文件中#号与$符号的区别:
1. #{} 占位符 prepareSatement 预编译
* ${value} 拼接字符串 satment 拼接
* "%"#{}"#" 可以将%放在这里进行拼接。
2. #{}和${}都是用来设置sql映射文件中statement参数的占位符,通过parameterType设置statemenet的参数类型,这里可以有string字符串、基本类型、pojo、map类型;
3. 区别:
* 安全性:#..可以防止sql注入,$..只是进行内容拼接不能避免
* 实现方式:#..是预编译写入 ,$.. 是拼接方式
* 如果只是单纯的设置参数就使用#{},而不用${}
* 使用场景:
* 表名是动态的: select* from ${value}
* like查询: select* from name like '%${value}%'
* 列名是动态的:
* 排序列是动态的:
* 总结:
* 在操作确定数据类型的情况下使用#{}
* 在操作不确定的数据类型的情况下使用${}
10.核心配置文件中的配置问题:
1.结果类型有三种:
1.数据类型
2.对象
3.列表(众多的数据类型或者对象)
2.在Windows中mysql不区分大小写,所以如果java中类属性大小写不一样也能匹配;Linux中mysql严格区分大小写。
3.在IUserDao.xml中,执行sql语句如果与属性参数对应不上的解决办法:
1.起别名: as; 执行效率高
* 将数据库中的列名起别名,使之与实体类属性一致。(执行效率最高,是从sql语句层面解决问题)
2.采用配置的方式; 开发效率高
* 在mapper标签下添加标签:
* <resultMap id="userMap" type="com.itheima.domain.User">
* <id property="userId" column="id"></id>
* <result property="userName" column="username"></result>
* <result property="userAddress" column="address"></result>
* <result property="userSex" column="sex"></result>
* <result property="userBirthday" column="birthday"></result>
* </resultMap>
* 同时:select标签添加:resultMap="userMap"属性;
* 虽然这个方法执行效率不高,但是只需要在上面配置好了,后面的每个select标签只需要添加resultMap属性即可,效率很高!
* property代表实体类,column代表数据库
3.实体类和数据库属性命名一致
4.可以在configuration标签内部配置连接数据库的信息,也可以通过属性引入外部配置文件信息。
1. resource属性:用于指定配置文件的位置,是按照类路径的写法来写,并且必须存在于类路径下。如:<properties resource="jdbcConfig.proties"> //这里是放在resource路径的根路径下。[推荐]
2. url属性:是要求按照Url的下发来写地址
* URL:Uniform Resource Locator: 统一资源定位符。它是可以唯一标识一个资源的位置。
* 它的写法:
* http://localHost:8080/mybatisserver/demo1Servlet
协议 主机 端口 URI
3. FIle协议:我们打开的资源都是file协议的,file:///C:/Users/...
* <properties url="file:///D:IdeaProjects/day02_eesy_01mybatisCRUD/src/main/resource/..."
11.传统方式:写实现类完成mybatis框架的持久层操作:
1.实现类:
* 在实现类中定义通过构造函数传入的工厂类。
* 在方法中使用工厂factory.openSession();获取SqlSession对象session
* 使用session.select...返回一个数据类型,对象或者列表
* 释放资源,返回结果
2.在测试类中:
* 读取字节码文件返回字节码inputStream
* 使用构建者模式创建工厂factroy
* 使用userDao调用实现类中的方法返回结果集
* 打印结果
3.注意:
* session.insert("全限定类名",有值的实体类);这样才能实现保存用户的操作。* session.fendByName("全限定类名",username);这里通过名字查询,则需要传入名字进去。
* 不带条件的即可不需要传入值。
12.使用代理Dao以及使用dao实现类的方式的区别
1.sqlSession.getMapper(IUserDao.class)
2.sqlSession.selectList()
3.一些技巧:
* ctrl+H 可以查看一个类的继承结构
* 找到某一个类的快捷键:Double Shift (Double就是按两下)
* 快速找到方法:Ctrl+F12
13.标签:
1. 起别名
1. 使用typeAliases配置别名,它只能配置domain中类的别名:
* <typeAliases>
* //方法一: <typeAlias type="com.itheima.domain.User" alias="User">
* //方法二: <package name="com.itheima.domain"></package>
* </typeAlias>
* </typeAliases>
2. 使用package,用于指定要配置别名的包,当包指定之后,这个可以用于环境配置和mappers映射文件位置的(package标签是用于指定dao接口所在的包,当指定了之后即不需要写mapper以及resource或者classes了)
* 为什么指定了就不用写了呢? 因为使用package标签指定了扫描的包,那么该包下的所有的该类型文件就不必要写class和resource了,因为class是表示注解,resource表示xml文件,如果有多个dao接口需要写多个class或者resource类型的映射配置,如果有了package就只需要写一次就够了,因为package是面向包路径,包含包下所有文件,而其他是面向文件的;
今日任务:
1. 使用代理dao的方式完成crud以及模糊查询
2. 使用自己实现dao实现类的方式完成crud
3. 尝试着理一遍源码的过程:代理dao以及实现类dao的方式