Oracle deadlock - how to use "synchronised" keyword in a transaction?

Hi,
I use WL6.1 SP4, Oracle 8.1.6, with some Java objects which execute a
lot
of SQL queries (mixed update, insert and select) using plain JDBC
calls,
and Weblogic connection pools. These objects are called by servlets.
I experienced recently deadlocks when two users call the object at the
same
time (See error below).
I execute the queries using "synchronized" keyword in the following
way:
synchronized (this)
conConnection.setAutoCommit(false);
executeTransaction(myStatement);
conConnection.commit();
executeTransaction is overriden in sub-classes and is the method which
executes
all the queries.
It calls methods in other objects. These methods are not declared as
synchronized.
1) Should they?
2) Should I use the keyword "synchronized" in another way?
3) This part of code is also called when I do only "select"
statements. I guess
it should only be synchronized when we do "update" and "insert" which
could lead
to a deadlock?
4) Do you have any idea why this deadlock occurs as I use the
"synchronized"
keyword, and one thread should wait until the other one has finished?
Thanks for any idea,
Stéphanie
----------------- error:
<ExecuteThread: '4' for queue: 'default'> <> <> <000000> <SQL request
sent to database: UPDATE PARTICIPANT par SET par.PARTICIPANTLASTRANK =
4 WHERE par.IDPARTICIPANT = 8983566>
<ExecuteThread: '11' for queue: 'default'> <> <> <000000> <SQL request
sent to database: UPDATE PARTICIPANT par SET par.PARTICIPANTLASTRANK =
6 WHERE par.IDPARTICIPANT = 8983570>
ORA-00060: deadlock detected while waiting for resource
     at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134)
     at oracle.jdbc.ttc7.TTIoer.processError(TTIoer.java:289)
     at oracle.jdbc.ttc7.Oall7.receive(Oall7.java:573)
     at oracle.jdbc.ttc7.TTC7Protocol.doOall7(TTC7Protocol.java:1891)
     at oracle.jdbc.ttc7.TTC7Protocol.parseExecuteFetch(TTC7Protocol.java:1093)
     at oracle.jdbc.driver.OracleStatement.executeNonQuery(OracleStatement.java:2047)
     at oracle.jdbc.driver.OracleStatement.doExecuteOther(OracleStatement.java:1940)
     at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:2709)
     at oracle.jdbc.driver.OracleStatement.executeUpdate(OracleStatement.java:796)
     at weblogic.jdbc.pool.Statement.executeUpdate(Statement.java:872)
     at weblogic.jdbc.rmi.internal.StatementImpl.executeUpdate(StatementImpl.java:89)
     at weblogic.jdbc.rmi.SerialStatement.executeUpdate(SerialStatement.java:100)
     at bfinance.framework.EDBBLBean.executeSQL(EDBBLBean.java:299)

Hi Stepanie,
I'd try to group update statement together. Usually it helps.
Regards,
Slava Imeshev
"Stephanie" <[email protected]> wrote in message
news:[email protected]...
Thanks for your answer.
In the case you describe, is there a way to ensure that tx-2 waits for
tx-1
to be finished before beginning?
My transaction which causes the problem is the following (simplified):
UPDATE tableA SET islast=0 WHERE externalid=myid;
for (int i=0; i< aVector.size(); i++) {
INSERT INTO tableA (id, islast, ranking, externalid) (SELECT
SEQ_tableA.nextval, 1, 0, myid);
UPDATE tableA SET ranking = /*calculated ranking */
WHERE externalid=myid AND islast=1;
UPDATE tableB ....
commit;
tx-1 and tx-2 execute this transaction at the same time. tx-1 begins
The deadlock appears when tx-2 executes the second UPDATE tableA
query.
I don't see how I can avoid to execute these two update queries, so if
I can find another way to prevent deadlock, it would be great!
Stéphanie
Joseph Weinstein <[email protected]_this> wrote in message
news:<[email protected]_this>...
Stephanie wrote:
Hi,
I use WL6.1 SP4, Oracle 8.1.6, with some Java objects which execute a
lot
of SQL queries (mixed update, insert and select) using plain JDBC
calls,
and Weblogic connection pools. These objects are called by servlets.
I experienced recently deadlocks when two users call the object at the
same
time (See error below).Hi. The error you are getting isn't necessarily from a lack ofsynchronization
of your java objects. It has to do with the order in which you accessDBMS
data. You are getting ordinary DBMS deadlocks, which are caused when
two DBMS connections each have a lock the other wants, in order toproceed.
The DBMS will quickly discover this and will kill one transaction inorder to
let the other one proceed:
time 0: tx-1 and tx-2 have started.....
time 1: tx-1: update tableA set val = 1 where key = 'A'
time 2: tx-2: update tableB set val = 2 where key = 'B'
time 3: tx-1: update tableB set val = 1 where key = 'B' (waitsbecause tx-2 has the row
locked)
time 4: tx-2: update tableA set val = 2 where key = 'A' (waitsbecause tx-1 has the row
locked)
This is a deadlock. The solution is to organize your application code sothat every
transaction accesses the data in the same order, eg: update tableAfirst, then update tableB.
This will prevent deadlocks.
Joe Weinstein at BEA
I execute the queries using "synchronized" keyword in the following
way:
synchronized (this)
conConnection.setAutoCommit(false);
executeTransaction(myStatement);
conConnection.commit();
executeTransaction is overriden in sub-classes and is the method which
executes
all the queries.
It calls methods in other objects. These methods are not declared as
synchronized.
1) Should they?
2) Should I use the keyword "synchronized" in another way?
3) This part of code is also called when I do only "select"
statements. I guess
it should only be synchronized when we do "update" and "insert" which
could lead
to a deadlock?
4) Do you have any idea why this deadlock occurs as I use the
"synchronized"
keyword, and one thread should wait until the other one has finished?
Thanks for any idea,
Stéphanie
----------------- error:
<ExecuteThread: '4' for queue: 'default'> <> <> <000000> <SQL request
sent to database: UPDATE PARTICIPANT par SET par.PARTICIPANTLASTRANK =
4 WHERE par.IDPARTICIPANT = 8983566>
<ExecuteThread: '11' for queue: 'default'> <> <> <000000> <SQL request
sent to database: UPDATE PARTICIPANT par SET par.PARTICIPANTLASTRANK =
6 WHERE par.IDPARTICIPANT = 8983570>
ORA-00060: deadlock detected while waiting for resource
at
oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134)
at oracle.jdbc.ttc7.TTIoer.processError(TTIoer.java:289)
at oracle.jdbc.ttc7.Oall7.receive(Oall7.java:573)
atoracle.jdbc.ttc7.TTC7Protocol.doOall7(TTC7Protocol.java:1891)
atoracle.jdbc.ttc7.TTC7Protocol.parseExecuteFetch(TTC7Protocol.java:1093)
atoracle.jdbc.driver.OracleStatement.executeNonQuery(OracleStatement.java:2047
atoracle.jdbc.driver.OracleStatement.doExecuteOther(OracleStatement.java:1940)
atoracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java
:2709)
atoracle.jdbc.driver.OracleStatement.executeUpdate(OracleStatement.java:796)
atweblogic.jdbc.pool.Statement.executeUpdate(Statement.java:872)
atweblogic.jdbc.rmi.internal.StatementImpl.executeUpdate(StatementImpl.java:89
atweblogic.jdbc.rmi.SerialStatement.executeUpdate(SerialStatement.java:100)
at bfinance.framework.EDBBLBean.executeSQL(EDBBLBean.java:299)

Similar Messages

  • Can i make Thread safe without using synchronised keyword in java

    Hi all,
    please tell me code and concept that we can make Thread safe without using synchronised keyword in java programming.
    regards
    Mohan kumar

    There's a series of new features in Java 5.0 (JDK 1.5.0) to address things like concurrency.
    See: http://java.sun.com/j2se/1.5.0/docs/guide/concurrency/overview.html
    -Alexis

  • How to Use native keyword in java programming

    Hi ,
    I am using JDK 1.6.0_11 , and i was trying to create a java program using "native" keyword ,
    i got the sample code for the same from the site : - http://www.javaworld.com/javaworld/javatips/jw-javatip23.html
    But when i type this command " C:\javah -stubs Happy " following error occurs
    " Error: JNI does not require stubs, please refer to the JNI documentation. "
    then typed " c:\javah -jni Happy" without any error .
    After that i wrote a HappyImpl.c as mentioned in the above tutorial
    #include <StubPreamble.h> /* Standard native method stuff. */
    #include "Happy.h" /* Generated earlier. */
    #include &ltstdio.h> /* Standard C IO stuff. */
    void Happy_printText (struct HHappy *this)
    puts ("Happy New Year!!!");
    then it is not compling and error is
    "unable to open included file StubPreamble.h file
    unable to open included file Happy.h file "
    Please help me . i want to use native method , i did exactly the same in tutorial at above link.
    Thanks & Regards
    Mannat

    you do need to know how to use your C compiler... It quite clearly can't find those files which indicates that you didn't tell it where to find them.

  • How to use Partner function in Purchase transactions(Purchase cycle)

    Hi,
    My issue is related to partner function i have defined the following customize setting .
    1) Defined partner role
    2)Defined Permissible Partner Roles per Account Group
    3)Defined Partner Schemas
    4)Assigned Partner Schemas to Account Groups
    5)Assigned Partner Schemas to Document Types
    6)created Partner role for vendor in vendor master given defrent vendor code for one partner type i.e given different vendor number to Invoice party (IP)
    7) crated PO and GR during IR when i click Detail tab there is Inv. Party Field which shows all the vendor master  i want only my Partner type there. how to archive this.
    actually my question is after define the Partner function how to use them in MIRO or MIGO i am not able to understand if some one know pls reply
    regards,
    Ashish Vats

    Hi
    The use of Standard Parner functions are as follows:
    1. Ordering Address (OA): The PO will be sent this vendor and not the main vendor.
    2. Goods Supplier (WL): In case of return deliveries, Goods will be returned to thsi vendor's address
    3. Invoicing party (RS): The payment will be made to this vendor.
    Hope this clarifies.
    Thansk

  • How to use Multiple Keywords in a Search Form?

    I'm currently using a bind variable on the view object to generate a search form where the user enters one keyword that is applied to the WHERE cause of the SQL query.
    The problem is I'm trying to implement a Google-type search, where the user can enter multiple keywords in a single text input area. I then want to parse out those keywords and search the database on each keyword (similar to a Google search.) Can someone please help me point me in the right direction as to where / how to code in the appropriate hooks to accomplish this?
    Example:
    (user input) Enter Search Keywords: keyword1 keyword2 keyword3.. keywordn
    database query:
    Select item from table where (desc like '%keyword1%') or .. (desc like '%keywordn%') or
    (category like '%keyword1%') or .. (category like '%keywordn%')

    Can't you parse what was entered and create a number of view criteria rows, then apply them? At that point, they would be 'OR'd together'.

  • How to use LIKE keyword in a select statement

    Hi:
    I want to use the following sql statement,
    String str = "xyz";
    String query="Select * from tab where col like '"+str+"' '%' ";
    Kindly suggest
    TIA

    % is a wildcard in the like clause, so:.
    String str = "xyz";
    String query="Select * from tab where col like '%"+str+"%'";

  • How to use Synchronized Keyword

    Hi guys,
    Sorry if this is a simple question, but I'm not sure about the following:
    Suppose we have the class,
    Class Foo
    public synchronized void bar1() {...}
    public synchronized void bar2() {...}
    If I have two threads running concurrently, say T1 and T2.
    I know that T1 and T2 can't both be in bar1() at the same time right? [It has to be in some serial order]
    But, can T1 be in bar1() and T2 be in bar2() at the same time?
    I guess the question is, does the synchronized apply to that specific method only? Or rather to the object (which basically limits at most one thread calling that object's synchronized methods)?
    Thanks a bunch! :)
    -Michael.

    Hi Michael,
    In general, when you syncronize a block of code, the execution of the block is syncronized ON an object. Any object can function as a lock, and only one thread can have a lock of one object at a time. If one thread already has a lock on an object and another thread tries to acquire lock on the same object, the latter thread will wait until the lock is released.
    When you use 'synchronized' in method declaration, it means that the execution of the whole method is syncronized on the object itself (NOT class, if the method is non-static. Static method would be synchronized on the .class object.)
    So, if you have more than one syncronized methods, only one of them is executed at a time ON THE SAME OBJECT. The same method can, of course, be executed simultaneously on other objects. Also, if some of the methods are synchronized, but other methods are not, the non-synchronized methods are not affected in any way.
    It might be good to note that these two pieces of code have exactly the same meaning:
    public synchronized doSomething() {
        // do something
    }and
    public doSomething() {
        synchronized (this) {
            // do something
    }Hope this helps.
    Cheers,
    Vesa
    p.s. It's a good idea to design your code so that one thread will have no more than one lock at a time. If it's possible for more than one thread to have lock on more than one object, there may be a risk of the threads dead-locking, which will crash any program...

  • How to use this sql query in oracle?

    Hi all,
    i am using one sql query that is
    SELECT @ToDate = '2012-10-03 00:00:00.000'
    select @BetweenDate = DATEADD(MM,-1,@ToDate)
    select @FromDate = DATEADD(m,DATEDIFF(m,0,@BetweenDate),0)
    SELECT @ToDate = DATEADD(month, ((YEAR(@BetweenDate) - 1900) * 12) + MONTH(@BetweenDate), -1)
    so @todate value is = '2012-10-03 00:00:00.000'
    so in @betweendate value will come 1 month before like '2012-09-03 00:00:00.000'
    again in @fromdate value will come like that '2012-09-01 00:00:00.000' means first date of @betweendate
    and again @todate value will come like that '2012-09-30 00:00:00.000' means last date of @betweendate
    it's happening in sql and i have to use same logic in oracle also.
    how to use it??
    thanks

    declare
    todate date:= to_date('2012-10-03 00:00:00','yyyy-mm-dd hh:mi:ss');
    betwendate date := add_months(todate,-1);
    for datediff / additions you can direct subtract/add two different date variables
    like
    datediff = betweendate -todate
    dateadd := todate+1;

  • How to use chain and endchain keywords?

    Hi i have got a requirement where i have to use chain and endchain keywords can anyone help me with the sample code how to use this keywords?

    Hi,
       Within a chain block, you must use ON CHAIN-INPUT addition. The module is then called if the conteents of at least one screen field within CHAIN block have changed from their intial value.
    Also, there is ON CHAIN-REQUEST addition, this module is called if user changes changes contents of atleast one screen field within CHAIN block..
    ON CHAIN-INPUT--
        PROCESS AFTER INPUT.
            CHAIN.
                FIELD : <Field name 1>,
                             <Field name 2>.
                 MODULE <module> ON CHAIN-INPUT
             ENDCHAIN.
    ON CHAIN-REQUEST--
         PROCESS AFTER INPUT.
            CHAIN.
                FIELD : <Field name 1>,
                             <Field name 2>.
                 MODULE <module> ON CHAIN-REQUEST
             ENDCHAIN.
    I hope u find this helpful..
    write brief about ur requirement??
    Regards,
    Vikram

  • How to use keyword exituFF1F

    Hello everyone, I have a question, how to use the keyword exit?
    I want to add something in F1.
    Thank you very much!
    Edited by: li zhu on Nov 7, 2008 10:35 AM

    @Shan Palani
    Nice Copy Paste Work From;
    [SAP Library : Creating Customer-specific Documentation|http://help.sap.com/saphelp_nw04s/helpdata/en/c8/19763443b111d1896f0000e8322d00/frameset.htm]
    Regards
    Karthik D

  • How to use tree tables with CRUD operation for begineers ADF 11g

    This is Friday night call for help.
    This is only few sample ressources on the web for tree table and only one with CRUD operation.
    I used this one http://jobinesh.blogspot.com/2010/05/crud-operations-on-tree-table.html because this is the only one that address CRUD.
    And it is shaky. Deletion works fine but insertion not very well. This is working using custom code provided below.
    Depending if the user selection in the tree, the code insert from the master node to the children node.
    Any other options because it is not working well.
    Also where Oracle describes how to use the row, rowset, itorator API? This is really hard to understand like almost if we should not use it.
    then if not how can I insert in tree with two nodes and insert in the parent or children depending the users selection.
    Lately I 'been posting questions on this forum with no response. This hurts. I understand developers cannot spend their time on this but People from Oracle, please help. We pay licenses...
    public void createChildren(RowIterator ri, Key selectedNodeKey) {
    final String deptViewDefName = "model.DepartmentsView";
    final String empViewDefName = "model.EmployeesView";
    if (ri != null && selectedNodeKey != null) {
    Row last = ri.last();
    Key lastRowKey = last.getKey();
    // if the select row is not the last row in the row iterator...
    Row[] found = ri.findByKey(selectedNodeKey, 1);
    if (found != null && found.length == 1) {
    Row foundRow = found[0];
    String nodeDefname =
    foundRow.getStructureDef().getDefFullName();
    if (nodeDefname.equals(deptViewDefName)) {
    RowSet parents =
    (RowSet)foundRow.getAttribute("EmployeesView");
    Row childrow = parents.createRow();
    parents.insertRow(childrow);
    } else {
    RowSet parents =
    (RowSet)foundRow.getAttribute("EmployeesView");
    Row childrow = parents.createRow();
    childrow.setAttribute("DepartmentId",
    foundRow.getAttribute("DepartmentId"));
    parents.insertRow(childrow);
    } else {
    System.out.println("Node not Found for " + selectedNodeKey);
    }

    I am looking for a sample that describe how to design a jsf page with a tree table.
    So you have Department and employees. In the tree first comes Department and if you click the node you see the employees assigned to this department.
    I need to be able to insert a new department or a new employee from the tree table by clicking on a insert button in the panel collection toolbar depending on user selection in the tree.
    I got part of it working but not good enough.
    By problem is the get insertion working
    I have a createChildren method in my AM implementation that get in input a RowIterator and selected node key.
    To goal is to create new records depending of the user selection and the input parameters get populated by the binding like this:
    #{backing_treeSampleBean.selectedNodeRowIterator} #{backing_TreeSampleBean.selectedNodeRowkey} via method binding with parameters.
    Is it the right approach?
    First to be able to insert a parent record, I select nothing in the tree and ri and selectedNodeKey comes to null
    we run this code
    ViewObjectImpl vo = getSchHolidaySchedExceptionsView1();
    //ViewObjectImpl vo = getDepartmentsView1();
    Row foundRow = vo.first();
    Row childrow = vo.createRow();
    vo.insertRow(childrow);
    A new blank entry appears in the parent node and we enter a value.
    The the problem starts when we want to add a child to this parent.
    We select the created parent and press the insert button, this code get executed
    if (nodeDefname.equals(deptViewDefName))
    //list of the children of the parent and create an new row
    RowSet childRows = (RowSet)foundRow.getAttribute("SchHolidayExceptionDatesView");
    Row childrow = childRows.createRow();
    childRows.insertRow(childrow);
    But the new entry does not appear, it is almost like it would be created for a different parent because this is a mandatory field that is not feel in yet and the interface complaints of a missing value. It is created somewhere just not a the right place... This is my guess.
    Do you see something wrong with the code?
    The full code og my create children method is there below
    I am using jdeveloper 11.1.1.3.0 any issues with tree table to know about with this version?
    Thanks for your help
    public void createChildren(RowIterator ri, Key selectedNodeKey) {
    final String deptViewDefName = "com.bcferries.app.pdfroutesched.model.SchHolidaySchedExceptionsView";
    final String empViewDefName = "com.bcferries.app.pdfroutesched.model.SchHolidayExceptionDatesView";
    if (ri != null && selectedNodeKey != null) {
    // last row
    Row last = ri.last();
    Key lastRowKey = last.getKey();
    // if the select row is not the last row in the row iterator...
    Row[] found = ri.findByKey(selectedNodeKey, 1);
    if (found != null && found.length == 1) {
    // foundRow is the row selected
    Row foundRow = found[0];
    // The row selected can be the parent node or the child node
    String nodeDefname = foundRow.getStructureDef().getDefFullName();
    // if parent row
    if (nodeDefname.equals(deptViewDefName))
    //list of the children of the parent and create an new row
    //works but we try to resolve the creation of a parent
    RowSet childRows = (RowSet)foundRow.getAttribute("SchHolidayExceptionDatesView");
    Row childrow = childRows.createRow();
    //childrow.setAttribute("HolidayDate", new java.util.Date().getDate());
    System.out.println("insert child row from master");
    childRows.insertRow(childrow);
    } else
    //RowSet ParentRow = (RowSet)foundRow.getAttribute("SchHolidaySchedExceptionsView");
    //RowSet childRows = (RowSet)ParentRow.first().getAttribute("SchHolidayExceptionDatesView");
    Row childrow = ri.createRow();
    System.out.println("insert child row from child ");
    } else {
    System.out.println("Node not Found for " + selectedNodeKey);
    } else {
    System.out.println(" param null try creating for first row : " +
    ri + " * " + selectedNodeKey);
    ViewObjectImpl vo = getSchHolidaySchedExceptionsView1();
    Row foundRow = vo.first();
    Row childrow = vo.createRow();
    vo.insertRow(childrow);
    }

  • Using synchronisation functions.

    Can you explain me how to use synchronisation functions in LabVIEW 7.0 ? With examples if possible ...
    Thanks

    This question is way too open-ended for a concise answer here.
    You need to do a little research and learing by using the NI Example Finder and looking around NI.com for examples. LabVIEW help is also very useful.
    Dave.
    ==============================================
    David Kaufman
    LabVIEW Certified Developer
    ==============================================

  • How to use maven project with fusion web application

    hi i have seen the tutoriel of oracle on how to use maven 2 with jdevelopper ,
    but how to integrate it on a fusion web application ???
    Edited by: 922454 on 9 avr. 2012 04:39

    If you have not managed to help yourself out with maven for ADF here is a quick workaround you can try. Invoke ant's ojdeploy task from maven. Refer step-by-step guide here.
    http://maveninjdeveloper.blogspot.in/2012/04/handle-adf-application-maven-ant.html

  • Regarding using 'Enhancement' keyword in ABAP

    Hi All,
                How to use ENHANCEMENT keyword in abap.
    Thks
    Shailesh

    Hi,
    Check out this
    http://help.sap.com/abapdocu/en/ABAPENHANCEMENT.htm
    Thanks,
    Krishna..

  • Display distinct rows from Oracle table without using "DISTINCT" keyword.

    How to retrieve distinct rows from oracle table without using 'DISTINCT' keyword in SQL?
    Thanks in advance.
    Mihir

    Welcome to the forum.
    Besides GROUP BY you can use UNIQUE instead of DISTINCT as well, but that's probably not wanted here ;) , and the ROW_NUMBER() analytic:
    SQL> create table t as
      2  select 1 col1 from dual union all
      3  select 1 from dual union all
      4  select 2 from dual union all
      5  select 3 from dual union all
      6  select 4 from dual union all
      7  select 4 from dual;
    Table created
    SQL> select col1 from t;
          COL1
             1
             1
             2
             3
             4
             4
    6 rows selected
    SQL> select distinct col1 from t;
          COL1
             1
             2
             3
             4
    SQL> select unique col1 from t;
          COL1
             1
             2
             3
             4
    SQL> select col1 from t group by col1;
          COL1
             1
             2
             3
             4
    SQL> select col1
      2  from ( select col1
      3         ,      row_number() over (partition by col1 order by col1) rn
      4         from   t
      5       )
      6  where rn=1;
          COL1
             1
             2
             3
             4

Maybe you are looking for

  • How small can I make the boot camp partition on my MacBookPro internal drive?

    it seems that in order to get Windows7 on to my old non supported MacPro 1.1 that I need to firist install onto this mid 2009 MacBook Pro I want to do the install onto an external firwire800 hard drive which I have formater and Downloaded and install

  • Conditions payment for my Craiglist item - Fraud?

    Is this email wanting me to ship my merchandise a fraud? PayPal logo 8 Dec 2014 Transaction ID: 3W492637HE3368307 Hello (my papal user name) You have an instant payment of $400.00 USD from Joshua Brown(ericwilli52...his email address) Note to seller

  • Third party AC char

    I just got a third-party AC outlet /?car USB charger for my Zen Microphoto. I don't know the power charging specifications and I don't want to power it incorrectly. This charger's power specification is 5V (+/- 0.2V) @ 500mAI have no idea what any of

  • Does any body knows how to make built in isight work with wondows xp!!!

    Hi everybody! I have the intel ship MacBook Pro, i'm runnining windows, i can't make it work, is there a plugin or a driver that i need to download, is there any body that can help me with this? please. Thanks. MacBook Pro   Windows XP Pro   built in

  • TOC Questions portrait view

    I see the TOC is based on the chapter titles of the book, I also see that you can change the styles and I need to know the following. Is there a way to add any other text to the titles for instance: chapter 1 - is the title ( which displays in the TO