一.MyBatis框架初使用
- 使用底层的selectOne()方法
- 导入Mybatis的jar包
- 创建一个全局配置文件 mybatis-config.xml ,根据全局配置文件,创建了一个
SqlSessionFactory对象. - 创建一个sql映射文件, EmployeeMapper.xml,该配置文件中配置了sql语句.
- 将sql映射文件注册到全局配置文件中
- 从SqlSessionFactory中获取SqlSession对象. sqlSession代表和数据库的一次会话.
- 然后调用selectOne(“sql语句的唯一标识”,执行sql的参数)完成查询操作.
- 最后将SqlSession对象关闭.释放资源.
将sql映射文件注册到全局配置文件中:
<mappers>
<!--<mapper resource="EmployeeMapper.xml"/>-->引入一个sql映射配置文件
<!--批量引入-->
<package name="com.atguigu.mybatis.dao"/>该包下方的配置文件全部引入
</mappers>
2.目录结构
二.Mapper接口开发
Mapper接口的好处:
1.接口中定义的方法明确的类型约束(方法参数的类型 方法返回值的类型)
2.接口本身:
接口本身就是抽象.抽出了规范.不强制要求如何做具体的实现.可以使用jdbc,hibernate,Mybatis.
接口将规范与具体的实现分离.
Mapper接口开发, MyBatis会为接口生成代理实现类。代理对象完成具体的增删改查操作.
最底层还是使用selectOne,update等方法来完成的.
Mapper接口开发需要注意:
1.Mapper接口要与sql映射文件动态绑定. sql映射文件的namespace指定成接口的全类名.
<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapper"></mapper>
2.Mapper接口方法与sql映射文件的sql语句绑定。 sql语句的id值指定成接口中的方法名.
<!--
select: 配置查询的sql语句
id:sql语句的唯一标识,不能重复,当添加上databaseId="XXX"时,即使用不同的数据库,此时id允许重复
resultType:当前sql查询到的数据想让MyBatis封装的javaBean对象的类型.
#{id}: 从传递过来的参数中取出id值.
-->
<!-- public Employee getEmpById(Integer id );-->
<!--sql语句的id值指定成方法名,目的是将sql语句与方法绑定-->
<select id="getEmpById" resultType="com.atguigu.mybatis.beans.Employee">
select id,last_name,gender,email from tb1_employee where id = #{id}
</select>
三.全局配置文件
1.properties
<!--
properties: Mybatis可以是用properties来引入外部properties类型的文件.
resource: 引入类路径下的资源
url: 引入网络路径或者是磁盘路径下的资源
-->
<properties resource="db.properties" ></properties>在db.properties中配置数据库的驱动,用户名等
2.settings
<!--
settings: 包含了很多重要的设置项
setting: 用来设置每一个设置项
name:设置项的名称
value:设置项的值
-->
<settings>
<!-- 自动映射下划线到驼峰命名 (数据库中常用下划线命名,JavaBean类中用大写命名)
DB: last_name autoMapping:lastName -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
3.typeAliases
<!--
typeAliases:别名处理,为java 类型注册别名
typeAlias: 为某个java类指定别名
type: 指定java的类型(包名+ 类名
alias: 指定具体的别名。 如果alias不显示的指定,则默认的别名是类名的首字母小
写.
别名不区分大小写。
package: 批量取别名.
name:指定包名。 为该包下的所的类取默认的别名。
批量取别名可能会出现别名冲突的情况. 例如指定的包下与子包下相同的类.
可以使用@Alias("别名")在类上标注具体的别名.
-->
<typeAliases>
<package name="com.atguigu.mybatis.beans"/>
<!-- <typeAlias type="com.atguigu.mybatis.beans.Employee" alias="emp" /> -->
</typeAliases>
4.environments
<!--
environments: 环境们。 使用default来指定具体使用的环境.
environment:配置具体的环境.
id: 当前环境的标识
transactionManager:事务管理器
type: 配置具体的事务管理器的类型
JDBC: JdbcTransactionFactory
MANAGED:ManagedTransactionFactory
最终: 事务管理要交给Spring. 使用Spring的声明式事务.
dataSource:数据源
type: 执行数据源的类型.
UNPOOLED:不使用连接池 UnpooledDataSourceFactory
POOLED:使用连接池 PooledDataSourceFactory
JNDI:从web服务器中获取数据源. JndiDataSourceFactory
最终: 数据源交给Spring管理
-->
<environments default="mysql">此处default配置那个id标识,使用的就是哪一个数据库
<environment id="mysql">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
<!--使用oracle数据库-->
<environment id="oracle">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${orcl.driver}" />
<property name="url" value="${orcl.url}" />
<property name="username" value="${orcl.username}" />
<property name="password" value="${orcl.password}" />
</dataSource>
</environment>
</environments>
5.databaseIdProvider
<!--
databaseIdProvider:
Mybatis用来支持多数据库厂商。Mybatis可以根据不同的数据库执行不同的sql语句
DB_VENDOR: VendorDatabaseIdProvider 作用就是得到数据库厂商的标识名.
Connection.getMetaData().getDataBaseProductName();
常见的数据库厂商的标识名:
MySQL: MySQL
Oracle: Oracle
SQL Server: SQL Server
-->
<databaseIdProvider type="DB_VENDOR">
<!-- 为数据库厂商的标识名起别名 -->
<property name="MySQL" value="mysql"/>
<property name="Oracle" value="oracle"/>
<property name="SQL Server" value="sqlserver"/>
</databaseIdProvider>
6.mappers
<!--
mappers: 引入sql映射文件
mapper: 引入单个的sql映射文件
resource: 引入类路径下的sql映射文件
url:引入网络路径或者是磁盘路径下的sql映射文件.
package: 批量引入sql映射文件
要求:
1.sql映射文件的名字与 Mapper接口的名字一致.
2.Sql映射文件与Mapper接口必须在同一目录下.
name:指定包名
-->
<mappers>
<!--<mapper resource="EmployeeMapper.xml"/>-->
<!--批量引入-->
<package name="com.atguigu.mybatis.dao"/>
</mappers>
sql映射文件
1.增删改查
<insert id="" parameterType="" databaseId="" >
<update>
<delete>
<select id="" parameterType="" resultType="" databaseId="">
如果想要获取到增删改对数据的影响条数,可以直接在接口的方法中声明返回值类型即可.
2.主键自增以及主键值的返回
-
a.对于支持自增主键的数据库(Mysql),可以使用useGeneratedKeys=“true”
keyProperty=“javaBean类的某个属性” -
b.对于不支持自增主键的数据库(oracle),使用selectKey的子标签完成主键值得返回.
selectKey的用法:
BEFORE: selectKey在插入语句之前执行
AFTER: selectKey在插入语句之后执行 -
c.Oracle数据库的自增策略:
使用序列模拟自增. 可以从序列中查询 nextval currval.
3.参数传递:
单个参数(普通类型(基本类型/包装类型+String)): Mybatis不会做特殊的处理
取值: #{参数名(随便写)} 取出参数值
多个参数:MyBatis会做特殊处理. 多个参数会被封装成一个Map。
封装map的规则:
key: param1 ,param2 , param3 ..... paramN / 0 1 2 ....N-1
value:具体传入的参数值
<!--测试传递多个参数的编写方式:public Employee getEmpByIdAndLastName(Integer id,String lastName);
select * from tb1_employee where id=#{param1} and last_name=#{param2}
当接口处明确标出Param时,这里可以使用对应的值来进行传参
public Employee getEmpByIdAndLastName(@Param("id")Integer id , @Param("lastName")String lastName);
-->
<select id="getEmpByIdAndLastName" resultType="com.atguigu.mybatis.beans.Employee">
select * from tb1_employee where id=#{id} and last_name=#{lastName}标明时可以使用对应值
</select>
异常: ### Cause: org.apache.ibatis.binding.BindingException: Parameter 'id' not found.
Available parameters are [1, 0, param1, param2]
解决: 取值使用#{param1/ 0} #{param2 / 1 }
1.命名参数**: 明确的指定多个参数封装map的时候所使用的key。 @Param(“key”)
取值: #{@Param指定的key/paramN}
2.POJO: 如果参数很多,正好又是业务逻辑的数据模型中的属性,直接传入POJO
取值: #{POJO的属性名}
3.Map: 如果参数很多,不是业务逻辑的数据模型中的属性,可以封装成map传入.
取值: #{map中的key}
map.put(“aa”,1001);
map.put(“bb”,“Tom”);
映射配置中:
select * from tb1_employee where id=#{aa} and last_name=#{bb}取key值
参数处理的源码分析
names={0=id,1=lastName}
args=[1001,Tom]
public Object getNamedParams(Object[] args) {
final int paramCount = names.size();
if (args == null || paramCount == 0) {
return null;
} else if (!hasParamAnnotation && paramCount == 1) {
return args[names.firstKey()];
} else {
final Map<String, Object> param = new ParamMap<Object>();
int i = 0;
for (Map.Entry<Integer, String> entry : names.entrySet()) {
param.put(entry.getValue(), args[entry.getKey()]);
// add generic param names (param1, param2, ...)
final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);
// ensure not to overwrite parameter named with @Param
if (!names.containsValue(genericParamName)) {
param.put(genericParamName, args[entry.getKey()]);
}
i++;
}
return param;
}
参数值的获取方式
1.#{}: 可以获取map中的值 或者是POJO对象属性的值。 还可以直接获取普通类型的参数.
2.${}: 可以获取map中的值 或者是POJO对象属性的值
区别:
#{}:是以预编译的形式将参数设置到sql语句中. PreparedStatement 防止sql注入.
${}:取出的值直接拼装到sql语句中.会有安全问题.
使用场景:
大部分情况下推荐使用#{},原生的jdbc不支持占位符的地方可以使用 ${}来进行动态的赋值.
例如在表名的位置可以使用${}来获取值
eg: select xxxxx from where 条件 order by 排序字段 排序方式 limit ?,?;
分表:
select * from 2016_salary ;
select * from 2017_salary ;
select * from ${year}_salary ;
用户选择2016年,则从2016_salary表查.