mybatis的概述:
mybatis是一个用java编写的持久层框架,它使用了ORM思想实现了结果集的封装。
ORM:
Object Relational Mappging 对象关系映射
简单的说:
就是把数据库表字段和实体类的属性对应起来,让我们可以操作实体类就实现操作数据库表。
window下的mysql不区分大小写,linux下的mysql严格区分大小写
自定义mybatis框架:
在ConfigurationBean中,
private Map mappers = new HashMap();
public Map setMappers(Map mappers){
/**
* 此处setter方法不能用:this.mappers=mappers;
* 因为mappers可能会有多个,如果用this,那么后面的mappers会覆盖上一个mappers;
* 变量声明的时候必须new HashMap(),否则第一次调用this.mappers会空指针,而且
* Map是一个接口,它的putAll()方法也没有明确的方法体。
*/
this.mappers.putAll(mappers);
}
mappers对象的key: String key1 = namespace + "." + id ;
mappers对象的value: mapper对象-->field: queryString(sql), resultType
最终ProxyMapper对象代理对象调用方法的时候,通过:
String methodName = method.getName();
String packageName = method.getDeclaringClass().getName();
String key2 = packageName + "." + methodName;
Mapper mapper = mappers.get(key2);
if(mapper!=null){"说明调用的接口方法找到了对应的映射配置文件的mapper"}
主配置文件的约束
映射配置文件的约束
mybatis的坐标
org.mybatis
mybatis
3.4.5
//读取sqlMapConfig.xml
InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
//加载配置文件,获取SqlSessionFactory对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
//获取单个SqlSession
SqlSession sqlSession = factory.openSession();
//获取DAO层接口代理对象
IUserDao userDao = sqlSession.getMapper(IUserDao.class)
.....
**SqlMapConfig.xml的配置**
```xml
<properties>
<property name="jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="jdbc.url" value="jdbc:mysql://localhost:3306/db3"/>
<property name="jdbc.username" value="root"/>
<property name="jdbc.password" value="root"/>
properties>
<properties resource="./jdbcConfig.properties">properties>
<typeAliases>
<typeAlias alias="user" type="com.baidu.User"/>
<package name="com.baidu.domain"/>
typeAliases>
<environments>
...
<property name="driver" value="${jdbc.driver}"/>
...
environments>
mappers(映射器)的配置:
<mapper resource=""/> //使用相对于类路径的资源,相对路径,xml配置
eg: <mapper reource="com/baidu/dao/IUserDao.xml"/>
<mapper class=""/> //使用mapper接口的全限定类名,全类名,注解配
eg: <mapper class="com.baidu.dao.UserDao"/>
<package name=""/> //注册指定包下的所有接口和映射配置文件,注意不要重名
eg: <package name="com.baidu.dao"/>
//配置映射文件的包路径必须跟接口的包路径一致,package会扫描映射文件包和接口包
//所以使用这个配置,既支持注解配置,又支持xml配置
//如果注解配置跟xml配置冲突了,就会报错
IUserDao.xml的配置
映射配置文件的注意事项:
1.接口全限定名与映射文件的namespace对应
2.接口中方法名与映射文件中sql语句的id对应
3.接口中方法参数与parameterType对应
4.接口中方法的返回值与resultType或者resultMap对应
<mapper namespace="com.itheima.dao.IUserDao">
<select id="queryUserByName" parameterType="com.baidu.domain.User" resultType="Integer">
select * from user where id = #{name};
select>
mapper>
mybatis底层每次都会: connection.setAutoCommit(false);
注意:增加、删除、修改操作时,必须提交事务:sesseion.commit();
parameterType 支持赋值普通类型(17种)、pojo类型(User)、pojo包装类型(QueryVo)
普通类型:byte/short/int/long/double/float/char/boolean,基本类型的包装类(8种),String
pojo类型:普通的javabean
QueryVo类型:pojo的包装类,多个pojo类型作为QueryVo的成员变量
<select id="queryUserByName" parameterType="参数类型">
//参数类型是普通类型
name = #{任意变量} //eg:#{hello}
//参数类型是pojo类型
name = #{pojo的属性值} //eg:#{name}
//参数是QueryVo类型, ognl取值
name = #{pojo包装对象的属性名称.pojo对象的属性值} //eg:#{user.name}
select>
${value}表示字符串拼接,value不能随便改,会造成sql注入问题
传入的是普通类型:${value} //模糊查询: '%${value}%'
传入的是pojo类型: ${pojo对象的属性名称}
传入的是pojo包装类型:${pojo包装对象的属性名称.对应的属性}
如果一个方法中有多个参数,并且参数都是普通数据类型,可以使用@Param注解解决参数注入问题
@Insert("insert into user values(#{username},#{password})")
testAddUser(@Param("username")String username,@Param("password")String password){ ... }
如果使用的xml配置,参数是多个普通数据类型,省略掉parameterType即可
#{}和${}的区别:
#{}是一个占位符,mybatis在处理#{}时,会将其转换成?,通过#{}可以实现PreparedStatement向占位符进行赋值,自动进行java类型和jdbc类型转换,可以有效防止sql注入问题
${}是字符串的替换,就是把${}替换成变量的值,通过${}可以将parameterType传入的值替换到sql中,且不进行jdbc类型转换
jdbc类型对应的就是mysql中的数据类型,自动进行jdbc类型转换的好处,比如java: 将new Date()封装到mysql中,new Date()得到的是Tue Sep 18 10:56:31 CST 2018,这个明显是跟mysql的Date类型不对应的,因此需要转换成jdbc类型
resultType 支持返回普通类型(17种),pojo类型
输出的是普通类型:resultType="int" //int本质上是输出Integer类型,如果必须要int类型,resultType="_int",基本数据类型都遵循"_基本数据类型";
输出的是pojo类型:resultType="com.baidu.domain.User" //User
输出的是列表:resultType="com.baidu.domain.User" //List<User>
实体类属性名称跟数据库的列名不匹配,如何处理?
第一种方式:
给sql语句的字段起别名,别名跟实体类属性值对应即可
select id as uid ,....
第二种方式:
resultMap 建立domain实体和数据库表的对应关系
<mapper>
<resultMap type="com.baidu.domain.User" id="userMap">
<id column="id" property="uid"/>
<result column="username" property="name"/>
<result column="age" property="uage"/>
resultMap>
<select id="queryUser" resultMap="userMap">
select * from user
select>
mapper>
type 属性:指定实体类的全限定类名
id 属性:给定一个唯一标识,是给查询 select 标签引用用的。
id 标签:用于指定主键字段
result 标签:用于指定非主键字段
column 属性:用于指定数据库列名
property 属性:用于指定实体类属性名称
配置插入操作后,封装插入数据的id
<insert id="insertUser" parameterType="com.baidu.domain.User">
insert into user values(null,"hello",23);
<selectKey order="AFTER" resultType="Integer" keyColumn="id" keyProperty="id">
select last_insert_id();
selectKey>
insert>
//执行完这个标签的代码后,会将插入数据的id封装到user对象中,如果user对象原来就有id,原有的id会被替换掉
模糊查询的配置:
<select id="findByName" parameterType="string" resultType="com.baidu.domain.User">
第一种方式: select * from user where name like '%${value}%' ;
第二种方式: select * from user where name like #{username};
select>
模糊查询的注意点:
当在SqlMapConfig.xml中动态配置数据库连接,<properties resource="JdbcConfig.properties">properties>时,通常我们会配置username=root,并且取值的时候也是用${username}来取;此时如果配置模糊
查询,比如username like '${username}' 由于mybatis先读取的SqlMapConfig.xml因此${username}得到的值
也只会是root;拼接到statement中就是 where username like 'root';最好解决方案就是配置JdbcConfig.properties时,都带上jdbc,比如jdbc.username