Mybatis学习
-
mybatis是将对象类和数据库的表进行一一映射,
-
多个表之间之间的映射关系,需要用mapper.xml来进行。
-
这个文件的创建位置一般是和类在一起的。
-
如果是person类,那么一般取名是personMapper.xml,
-
里面的内容大致是这样的,
namespace=“xxx.xxx.xxx.personMapper”>这个是全类名,也就是这个person的全类名
标签里的id是用来区分查询哪一个的select的,这个resultType是一个返回值,因为是查询所 有,所以就可以返回一个Person对象。如果查询的是int类型,这里就可以改为int#{id}是动态传值相当于jdbc里的 ?。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xxx.xxx.xxx.personMapper">
<select id="selectBlog" resultType="Person">
select * from Blog where id = #{id}//切记,没有;
</select>
</mapper>
-
[id]:statement的id,要求在命名空间内唯一
[parameterType]:入参的java类型
[resultType]:查询出的单条结果集对应的java类型
[#{}]: 表示一个占位符?[#{id}]:表示该占位符待接收参数的名称为id。注意:如果参数为简单类型时,#{}里面的参数名称可以是任意定义 -
要想正确启动,需要在配置文件中添加你的这个类的xml文件
运行主文件:
//加载mybatis配置文件这里是程序检测时的主程序
Reader reader = Resources.getResourceAsReader("mybatis.xml");
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader,"");
SqlSession sqlSession = sqlSessionFactory.openSession();
String statement = "com.ypl.entity.UserMapper.findUserById";
User user=sqlSession.selectOne( statement,1);
System.out.println(user.toString());
//关闭连接
sqlSession.close();
错误总结
首先今天就只是个简单的实现mybatis的id查找就出现一堆错误
- 类的xml配置文件是否加到了主xml中,是否有log4j配置文件,类路径是否写错,xml文件放在jsrc的ava路径下,不能访问是否在pom.xml中添加了以下内容
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
- mapper文件中namepace的值是否有,是否被正确引用
- 类配置文件中这里要修改 <?xml version="1.0" encoding="UTF8" ?>
<environments default="development">
<environment id="development">
<!-- 配置JDBC事务控制,由mybatis进行管理 -->
<transactionManager type="JDBC"/>
<!-- 配置数据源 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&userUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="1024101159..ln"/>
</dataSource>
</environment>
</environments>
这里的<environments>
标签里面可以配置多个环境,
- 他有一个属性叫做*
default
*用来指定默认的环境, - 每个环境里都可以进行不同的数据库配置,
- 如果指定了默认的数据库但是想使用其他数据库,我们可以在主程序运行代码做这些改变
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder()
.build(reader,"指定的数据库环境id");
- POOLED是数据库连接池,UNPOOLED是不用数据库连接池,他就是使用传统的jdbc操作
- Mybatis在语法上只允许有一个输入值,有一个输出值
也就是说在类mapper文件中不同的标签只能有一个parameterType="" 和resultType=""
- 如果输入参数:是简单类型(八个基本数据类型+String) 是可以使用任何占位符,#{xxx}
如果是对象类型,则必须是对象的属性 #{属性名} - 输出参数: 如果返回值类型是一个 对象 (如Student),则无论返回一个。还是多个,在这个返回的类型中都写上 全类名
Mybatis接口没有实现类
约定:
约定的过程:
- 根据 接口名找到mapper.xml文件(根据的是namespace=接口全类名)
- 根据 接口的方法名找到在mapper.xml该文件中的SQL标签(根据的是 方法名=SQL的ID值)
以上两点可以保证:当我们调用接口中的方法时,程序能自动定位到某一个Mapper,xml文件中的SQL标签
优化:
- 可以将配置信息单独放进配置文件当中,然后在动态引入,
db.properties
k=v
引入之后,使用时用${k}进行取值,这样就可以将V值取出 - 设置别名:
(1)单独设置别名时 大小写无所谓
<!--设置单个或者多个别名-->
<typeAliases>
<!--设置单个别名-->
<typeAlias type="com.ypl.entity.User" alias="User"/>
</typeAliases>
(2)批量设置别名
<typeAliases>
<!--设置单个别名-->
<typeAlias type="com.ypl.entity.User" alias="User"/>
<!--批量定义别名,别名就是该类名-->
<package name="com/ypl/entity"/>
</typeAliases>
类型转换
<select id="findUserById" parameterType="int" resultMap="userResult" resultType="com.ypl.entity.User">
select *
from user
where id = #{id}
</select>
<resultMap id="userResult" type="User">
<!-- 分为主键id和非主键result-->
<!-- 属性和列名一一对应起来了-->
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="birthday" column="birthday"/>
<result property="sex" column="sex"/>
<result property="address" column="address" />
<!-- 类型转换 javaType="boolean" jdbcType="Integer",将布尔类型转换为integer类型-->
</resultMap>
在进行增删改操作时,发现都没有改变,最后得出原因是因为 没有commit,我们只需要一行代码即可sqlSession.commit();
输入参数:parameterType
- 类型为简单类型(8个基本类型+String)
#{任意值}
${value},其中的标识符只能是value
#{}自动给String类型加上’’(自动类型转换)
${}原样输出,但是适合于 动态排序(动态字段) - 对象类别
#{属性名}
${对象的属性名},其中的标识符只能是value
select * from user where username=#{value}
select * from user where username='${value}'
动态排序:
select * from user order by ${value} asc
3. #{}可以防止SQL注入,${不可以防止SQL注入}
在SQL语句中的if标签里,左边是数据库的字段,右边是属性名,严格区分大小写,使用mybatis简单顺序
- 先写工具类
private static SqlSessionFactory sqlSessionFactory;
static {
try {
//使用mybatis第一步,创建 SqlSessionFactory对象
String resource = "mybatis-config.xml";
Reader inputStream = Resources.getResourceAsReader(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession();
}
- 在写实体类
- 写配置类(config.xml)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<properties resource="db.properties"/>
<typeAliases>
<typeAlias type="com.ypl.pojo.User" alias="User"/>
<!-- <package name="com.ypl.pojo"/>-->
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 所有的路径以斜杠结尾-->
<!-- <mapper resource="com/ypl/dao/UserMapper.xml"/>-->
<package name="com.ypl.dao"/>
</mappers>
</configuration>
- 写mapper接口
- 写mapper接口的xml文件
- 在写测试类Test
引入mapper资源的方式
<!-- 使用相对于类路径的资源引用 --> <mappers>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 使用完全限定资源定位符(URL) --> <mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 需要配置文件名称和接口名称一致,并且位于同一目录下 --> <mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 但是需要配置文件名称和接口名称一致,并且位于同一目录下 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
动态SQL
where标签会自动处理第一个if标签里的and但不会处理之后的if标签里的and,if标签
在配置文件里的数据库信息使用中,它是优先使用配置文件db.properties,然后才是properties标签里的内容
生命周期和作用域
生命周期和作用域是至关重要的,因为错误的使用会导致严重的并发问题
1. SqlsessionFactoryBuilder
• 一旦创建了SqlsessionFactory,就不再需要他了
• 局部变量
2. SqlsessionFactory
• 可以将它想象为数据库连接池
• SqlSessionFactory一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃他或重新创建另一个实例
• 程序开始他就开始,程序结束他就结束
• 最简单的就是使用单例模式或者静态单例模式
SqlSession
• 连接到连接池的一个部分
• Sqlsession不是一个线程安全的,因此是不能被共享的,所以它的最佳作用域是请求或方法作用域
• 用完之后需要赶紧关闭,否则资源被占用!
日志工厂
• 如果一个数据库操作出现了异常。我们需要排错
•
• 注意大小写,不能有空格。
日志工厂简单使用:
- 在要使用log4j的类中,导入包import org.apache.log4j.Logger;
- 日志对象,参数为当前类的class
static Logger logger = Logger.getLogger(UserDaoTest.class);
• 日志级别
logger.info("info:进入了testLoj4");
logger.debug("debug:进入了testLoj4");
logger.error("error:进入了testLoj4");
分页
思考:为什么要分页
使用limit分页
select * from user limit startIndex,pageSize
如果这个startIndex是0,pageSize是2,那么查询出来的结果是从第1个开始,第2个结束
pageSize是负数,则是最后一个结束,但是他被修复了,现在不能用了
在使用注解开发
时:
在config.xml文件中绑定的是接口
关于Param注解
• 基本类型的参数或者String类型的参数需要加上
• 引用类型不用加
• 如果只有一个基本类型的话,可以忽略,但是建议加上
• 我们在SQL中引用的就是该注解里所设定的属性名
按照查询嵌套处理
<select id="getStudent" resultMap="StudentTeacher">
# select student.id,student.name,teacher.name from teacher,student where teacher.id=student.tid;
select *
from student;
</select>
<resultMap id="StudentTeacher" type="Student">
<!-- result 只能针对单一属性-->
<result property="id" column="id"/>
<result column="name" property="name"/>
<!-- association多个属性
复杂的属性要单个处理
对象要用association
集合使用collection
-->
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="Teacher">
select *
from teacher
where id = #{id}
</select>