编辑:找到解决方案,往下看.
我们有一个Web应用程序,它调用存储在Sql Server 2012数据库上的视图上的select .
此查询失败并显示错误
"New request is not allowed to start because it should come with valid transaction descriptor"
Run Code Online (Sandbox Code Playgroud)
此问题仅发生在单个客户数据库上,在所有其他客户模式上执行的相同查询运行正常.
在受影响的模式上在SSMS中自己执行的查询运行正常,仅在该特定模式的应用程序中失败.
SELECT语句是这样的:
select distinct clienti.numeroCliente,clienti.ragioneSociale,clienti.partitaIva,clienti.codiceFiscale,
clienti.SedeLegale,
clienti.mail,clienti.codiceContabilita,clienti.riferimentiCliente
from dbo.view_table clienti
where clienti.azienda = 'Company_name'
Run Code Online (Sandbox Code Playgroud)
如果我们在其他Sql Server实例上本地恢复架构,我们可以复制错误.
我在互联网上搜索了很多,我找到的只是Sql Server 2005的修补程序(https://support.microsoft.com/en-us/help/939285/fix-error-message-when-you-run-a -stored -程序-即-开始-A-交易是-包含-A-的Transact-SQL语句,在-SQL服务器2005年新请求时,不被允许到启动,因为,它-should-come-with-valid-transaction-descriptor)和一些与分布式查询和索引碎片相关的帖子.
鉴于我可以复制这个问题,我可以尝试解决它吗?
运行查询的spring后端是Java,一个通过Hibernate运行的本机sql查询.
Java 8
春季4.1.1
Hibernate 4.3.5
这是代码:
@Transactional(readOnly=true, isolation=Isolation.READ_UNCOMMITTED)
public List<ControlloContratto> caricaControlloContratti(FilterControlloContratti filter) {
List<ControlloContratto> lstCtrlContratti = null;
String dwhExtractionCCPQuery = "";
Session session = sessionManager.getFilteredSession(FilterType.NONE);
dwhExtractionCCPQuery = caricaControlloContrattiQuery(filter);
Query queryCallSP …
Run Code Online (Sandbox Code Playgroud) 我们开发了一个用Java编写并用Hibernate映射的HR应用程序; 其中一个特点是招聘阶段.
该Candidate
班是仿照这样的:
public class Candidate {
private String id;
private Integer candidateCode;
private GregorianCalendar birthDate;
private String italianFiscalCode; //unique code for italian people
}
Run Code Online (Sandbox Code Playgroud)
由于我们只为市场开发到目前为止,代码非常依赖于特定的立法,所以请查看fiscalCode
类属性.
请求是我们概括这个概念以便能够扩展到其他市场,例如唯一标识符可以是不同的,可以由几个字符串组成或根本不存在.
在我脑海中浮现的第一件事:
1 - 只需将字段重命名为countryIdentifier,并根据特定国家/地区的需要添加其他字段.
private String countryIdentifier; //general unique code
private Integer greekAddedCode;
Run Code Online (Sandbox Code Playgroud)
这意味着在需要的地方重构代码(所有放置旧的italianFiscalCode的地方),重命名DBMS列(并最终添加其他代码)并修改使用该字段的所有查询.
这对我来说看起来很糟糕
2 - 子类Candidate
创建ItalianCandidate
和GreekCandidate
移动子类中的特定字段.
问题是Candidate
该类已经被子类化,HeavyCandidate
它具有优化Hibernate映射的唯一功能,因为我们在重类中移动所有"重"属性(多对一和多组)(这是我们遵循的方法与我们所有的豆类).
在这种情况下,最正确的方法是什么?
在我的公司,我们在 Spring(Flex 前端)中开发一个企业 Web 应用程序,并以 SAAS 风格在 Tomcat 6 中将该应用程序部署给我们的客户。
最近,我们遇到了(看似)随机的 OutOfMemory 错误,因此经过调查,我知道我们应该在错误发生时检查 JVM 的内存转储。
我们使用的JVM是1.6.18,Tomcat版本是Windows Server 2008下的Tomcat 7.0.23。
我在 Tomcat 监视器面板(在 Java 选项卡下)中添加了参数 -XX:+HeapDumpOnOutOfMemoryError,但机器没有生成任何转储。
在我们正在调查的服务器上,完整的 java 选项设置如下:
-Dcatalina.home=C:\Program Files\Apache Software Foundation\Tomcat 7.0
-Dcatalina.base=C:\Program Files\Apache Software Foundation\Tomcat 7.0
-Djava.endorsed.dirs=C:\Program Files\Apache Software Foundation\Tomcat 7.0\endorsed
-Djava.io.tmpdir=C:\Program Files\Apache Software Foundation\Tomcat 7.0\temp
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
-Djava.util.logging.config.file=C:\Program Files\Apache Software Foundation\Tomcat 7.0\conf\logging.properties
-XX:PermSize=128m
-XX:MaxPermSize=1024m
-Xms1024m
-Xmx6144m
-XX:+HeapDumpOnOutOfMemoryError
-Dcom.sun.management.jmxremote.port=3333
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,最大堆大小非常大(6 Gigs),因为我们的应用程序特别重。出于测试原因,我添加了 jmx 参数,以便使用 VisualVM 实时查看 JVM 状态,但在查看时没有发生任何情况。
stderr 显示的所有内容如下:
java.lang.OutOfMemoryError
Run Code Online (Sandbox Code Playgroud)
它之前没有任何内容(除了我不知道是否相关的其他错误,但它们是在 OOM 之前数小时或几分钟记录的),之后也没有任何内容。
我觉得奇怪的是它没有报告内存部分(Java 堆大小,或 Permgen Space)。 …
我想解决的问题是:
1 - 在我们的数据库中,我们拥有所有表(也包含数百万条记录的表),其中PK id列声明为VARCHAR(36).它上面还有一个聚簇索引当然,当我在线阅读时,它对于性能来说是一件糟糕的事情,也因为db有很多读取,插入,更新和删除.
2 - 我们将Java Web应用程序的Hibernate用作此数据库的ORM
在线阅读后,我开始使用默认选项newsequentialid()将这些列的数据类型更改为UNIQUEIDENTIFIER,因为此选项可以缓解索引的碎片问题.
我注意到碎片问题仍然存在,重建后表格变得非常碎片化(我们每晚都进行完整的索引重建).
然后我看到id列的所有Hibernate映射都包含:
<id name="id" column="id" type="string">
<generator class="guid"/>
</id>
Run Code Online (Sandbox Code Playgroud)
当在我们的系统中发生插入时,日志显示插入是在调用之后完成的select newid()
,因此由于这会返回一个随机guid,插入将被放置在索引中的随机点,从而导致碎片(这完全打败了列数据类型更改)我也做了).
所以在另一次在线搜索之后,我试图在Hibernate中实现一个guid生成器,实现接口IdentifierGenerator
并使用基于时间的生成器和JUG(http://wiki.fasterxml.com/JugHome).
生成(我认为顺序)id的代码是这样的:
String uuid = null;
EthernetAddress nic = EthernetAddress.fromInterface();
TimeBasedGenerator uuidGenerator = Generators.timeBasedGenerator(nic);
uuid = uuidGenerator.generate().toString();
Run Code Online (Sandbox Code Playgroud)
我相应地改变了映射到这个:
<id name="id" column="id" type="string">
<generator class="my_package.hibernate.CustomSequentialGuidGenerator">
</generator>
</id>
Run Code Online (Sandbox Code Playgroud)
然后我尝试生成一些测试uuids来测试它们的顺序性(以uniqueidentifier方式顺序,所以二进制),这是一个短列表(每个元素在连续之前生成):
314a9a1b-6295-11e5-8d2c-2c27d7e1614f
3d867801-6295-11e5-ae09-2c27d7e1614f
4434ac7d-6295-11e5-9ed1-2c27d7e1614f
491462c4-6295-11e5-af81-2c27d7e1614f
5389ff4c-6295-11e5-84cf-2c27d7e1614f
57098959-6295-11e5-b203-2c27d7e1614f
5b62d144-6295-11e5-9883-2c27d7e1614f
Run Code Online (Sandbox Code Playgroud)
这看起来像按字母顺序排列,但不是二进制顺序.
上面的测试是在测试应用中执行了七次,它不是一个循环.
我试图在声明为唯一标识符的列中插入这些值,并在此列上发出select之后,这是sql server输出的列表:
5389FF4C-6295-11E5-84CF-2C27D7E1614F
314A9A1B-6295-11E5-8D2C-2C27D7E1614F
5B62D144-6295-11E5-9883-2C27D7E1614F
4434AC7D-6295-11E5-9ED1-2C27D7E1614F
3D867801-6295-11E5-AE09-2C27D7E1614F
491462C4-6295-11E5-AF81-2C27D7E1614F
57098959-6295-11E5-B203-2C27D7E1614F
Run Code Online (Sandbox Code Playgroud)
所以我真的不明白我应该做什么,如果我可以使用JUG作为顺序guid生成器来避免我的碎片问题.
这是另一个JUG测试,我尝试了3次运行,每次生成10个带有循环的guid: …
java ×4
hibernate ×3
sql-server ×2
dump ×1
guid ×1
inheritance ×1
jvm ×1
oop ×1
sql ×1
tomcat ×1