mybatis的#{}和${}区别
#{}和${}
#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。
但是有时用${}会非常方便,如下的例子:
<!-- 根据名称模糊查询用户信息 -->
<select id="selectUserByName" parameterType="string" resultType="user">
select * from user where username like '%${value}%'
</select>
如果本例子使用#{}则传入的字符串中必须有%号,而%是人为拼接在参数中,显然有点麻烦,如果采用${}在sql中拼接为%的方式则在调用mapper接口传递参数就方便很多。
//如果使用占位符号则必须人为在传参数中加%
List<User> list = userMapper.selectUserByName("%管理员%");
//如果使用${}原始符号则不用人为在参数中加%
List<User>list = userMapper.selectUserByName("管理员");
再比如order by排序,如果将列名通过参数传入sql,根据传的列名进行排序,应该写为:
ORDER BY ${columnName}
如果使用#{}将无法实现此功能。
mysql自增主键返回
通过修改sql映射文件,可以将mysql自增主键返回:
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
<!-- selectKey将主键返回,需要再返回 -->
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
select LAST_INSERT_ID()
</selectKey>
insert into user(username,birthday,sex,address)
values(#{username},#{birthday},#{sex},#{address});
</insert>
添加selectKey实现将主键返回
keyProperty:返回的主键存储在pojo中的哪个属性
order:selectKey的执行顺序,是相对与insert语句来说,由于mysql的自增原理执行完insert语句之后才将主键生成,所以这里selectKey的执行顺序为after
resultType:返回的主键是什么类型
LAST_INSERT_ID():是mysql的函数,返回auto_increment自增列新记录id值。
mybatis与hibernate的区别
Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句,不过mybatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。
Mybatis学习门槛低,简单易学,程序员直接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。
mybatis:专注是sql本身,需要程序员自己编写sql语句,sql修改、优化比较方便。mybatis是一个不完全 的ORM框架,虽然程序员自己写sql,mybatis 也可以实现映射(输入映射、输出映射)。
应用场景:
适用与需求变化较多的项目,比如:互联网项目。
Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例如需求固定的定制化软件)如果用hibernate开发可以节省很多代码,提高效率。但是Hibernate的学习门槛高,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡,以及怎样用好Hibernate需要具有很强的经验和能力才行。
总之,按照用户的需求在有限的资源环境下只要能做出维护性、扩展性良好的软件架构都是好架构,所以框架只有适合才是最好。
hibernate:是一个标准ORM框架(对象关系映射)。入门门槛较高的,不需要程序写sql,sql语句自动生成了。
对sql语句进行优化、修改比较困难的。
应用场景:
适用与需求变化不多的中小型项目,比如:后台管理系统,erp、orm、oa。。
企业进行技术选型,以低成本 高回报作为技术选型的原则,根据项目组的技术力量进行选择。
原始dao开发方法与mapper代理方法区别
(1)原始dao开发方法(程序员需要写dao接口和dao实现类)
程序员需要写dao接口和dao实现类。
需要向dao实现类中注入SqlSessionFactory,在方法体内通过SqlSessionFactory创建SqlSession
单独使用mybatis示例java代码:
String resource="SqlMapConfig.xml";
InputStream inputstream=Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory=new SqlSessionFactorySqlSessionFactoryBuilder().build(inputstream);
SqlSession sqlSession=sqlSessionFactory.openSession();
List<Student> studentList=sqlSession.sqlSession.selectOne("student.selectById", id);
......
其中studentList=sqlSession.sqlSession.selectOne("student.selectById", id);
其实就是在结合Spring框架时包装在Dao方法里进行调用,如下:
public class StudentDaoImpl extends SqlSessionDaoSupport implements StudentDao {
@Override
public Student selectById(int id) {
// TODO 自动生成的方法存根
SqlSession sqlSession=this.getSqlSession();
Student student=sqlSession.selectOne("student.selectById", id);
return student;
}
......
原始 dao方法开发问题
1、dao接口实现类方法中存在大量模板方法,设想能否将这些代码提取出来,大大减轻程序员的工作量。
2、调用sqlsession方法时将statement的id硬编码了
3、调用sqlsession方法时传入的变量,由于sqlsession方法使用泛型,即使变量类型传入错误,在编译阶段也不报错,不利于程序员开发。
4.mybatis的前身是ibatis,ibatis不支持mapper代理方法,只支持原始 dao开发方法
(2)mapper代理方法(程序员只需要mapper接口(相当 于dao接口))
Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。
Mapper接口开发需要遵循以下规范:
1、Mapper.xml文件中的namespace与mapper接口的类路径相同。
2、 Mapper接口方法名和Mapper.xml中定义的每个statement的id相同
3、Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同
4、Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
单独使用mybatis示例java代码:
String resource="SqlMapConfig.xml";
InputStream inputstream=Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputstream);
SqlSession sqlSession=sqlSessionFactory.openSession();
DepartmentMapper departmentMapper=sqlSession.getMapper(DepartmentMapper.class);
List<Department> departments=departmentMapper.findDepartmentStudentResultMap();
......
其中departmentMapper=sqlSession.getMapper(DepartmentMapper.class);
相比原始dao开发方法,在结合Spring框架时mapper代理方法只需要直接调用即可,不需要写Dao类。
mapper代理对象内部调用selectOne或selectList
动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。
mybatis官方推荐使用mapper代理方法开发mapper接口,程序员不用编写mapper接口实现类,使用mapper代理方法时,输入参数可以使用pojo包装对象或map对象。
注意:mapper代理方法同POJO基础类一样,是自动生成的,里面一般使用扩展类继承基础类,因为基础类都是自动生成的。
(3)体现mapper代理方法优势是在结合Spring情况下,示例代码如下:
原始 dao方法程序员需要编写Dao接口类和实现类:
applicationContext.xml
<!-- 原始dao配置 -->
<bean id="studentDao" class="ssm.dao.StudentDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
StudentDaoImpl.java
public class StudentDaoImpl extends SqlSessionDaoSupport implements StudentDao {
@Override
public Student selectById(int id) {
// TODO 自动生成的方法存根
SqlSession sqlSession=this.getSqlSession();
Student student=sqlSession.selectOne("student.selectById", id);
return student;
}
......
继承SqlSessionDaoSupport类,SqlSessionDaoSupport类的getSqlSession()方法返回SqlSessionTemplate对象,不需要关闭sqlSession,SqlSessionTemplate对象已经封装好事务提交及关闭操作。
调用:`
StudentDao studentDao=(StudentDao) applicationContext.getBean("studentDao");`
Student student=studentDao.selectById(3);
对比mapper代理方法:
applicationContext.xml
<!-- 批量使用扫描也需要遵循一些规范,spring配置该扫描后,sqlmapconfig配置文件无需再次配置mapper。xml也可以
遵循规范:需要将mapper接口类名和mapper。xml映射文件名称保持一致,且在同一个目录中 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 指定扫描的包名 -->
<property name="basePackage" value="ssm.mapper"></property>
<!-- 这个属性一般都用不到,只有当你配置多数据源的时候,这是会有多个sqlSessionFactory, -->
<!-- 你就需要通过该属性来指定哪一个sqlSessionFactory(值为SqlSessionFactoryBean <bean>配置中的id属性)。 -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
StudentMapper.java
public interface StudentMapper {
public Student selectById(int id) throws Exception;
// 综合条件查询
public List<StudentCustom> findStudentList(StudentQueryVo studentQueryVo) throws Exception;
调用:
StudentMapper studentMapper=(StudentMapper) applicationContext.getBean("studentMapper");
Student student=studentMapper.selectById(3);
使用mapper代理方法,MapperFactoryBean底层依然是封装了SqlSessionTemplate,SqlSessionTemplate对象已经封装好事务提交及关闭操作,同样只需调用增,删,改的方法就可以。
SqlMapConfig.xml文件元素:
1.properties(属性)
SqlMapConfig.xml可以引用java属性文件中的配置信息如下:
在classpath下定义db.properties文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=mysql
SqlMapConfig.xml引用如下:
<properties resource="db.properties"/>
<environments default="development">
<environment id="development">
<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>
</environments>
注意: MyBatis 将按照下面的顺序来加载属性:
在 properties 元素体内定义的属性首先被读取。
然后会读取properties 元素中resource或 url 加载的属性,它会覆盖已读取的同名属性。
最后读取parameterType传递的属性,它会覆盖已读取的同名属性。
例子如下:
<select id="findUserByUsername" parameterType="string" resultType="user">
select * from user where username like '%${jdbc.username}%'
</select>
如果传入的参数没有jdbc.username,就会从properties文件中加载。
因此,通过parameterType传递的属性具有最高优先级,resource或 url 加载的属性次之,最低优先级的是 properties 元素体内定义的属性。
建议:
不要在properties元素体内添加任何属性值,只将属性值定义在properties文件中。
在properties文件中定义属性名要有一定的特殊性,如:XXXXX.XXXXX.XXXX
2.mappers(映射器)
Mapper配置的几种方法:
<mapper resource=" " />
使用相对于类路径的资源
如:<mapper resource="sqlmap/User.xml" />
<mapper url=" " />
使用完全限定路径
如:<mapper url="file:///D:\workspace_spingmvc\mybatis_01\config\sqlmap\User.xml" />
<mapper class=" " />
使用mapper接口类路径
如:<mapper class="cn.itcast.mybatis.mapper.UserMapper"/>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
<package name=""/>
注册指定包下的所有mapper接口
如:<package name="cn.itcast.mybatis.mapper"/>
注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。
3.typeAliases(类型别名)
mybatis支持别名:
别名 映射的类型
_byte byte
_long long
_short short
_int int
_integer int
_double double
_float float
_boolean boolean
string String
byte Byte
long Long
short Short
int Integer
integer Integer
double Double
float Float
boolean Boolean
date Date
decimal BigDecimal
bigdecimal BigDecimal
自定义别名:
在SqlMapConfig.xml中配置:
<typeAliases>
<!-- 单个别名定义 -->
<typeAlias alias="user" type="cn.itcast.mybatis.po.User"/>
<!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以,一般小写) -->
<package name="cn.itcast.mybatis.po"/>
<package name="其它包"/>
</typeAliases>